diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 00000000..27508b67 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,311 @@ +# XDK SDK Generator: Technical Architecture + +## Overview + +The XDK (X Development Kit) Generator is a powerful, language-agnostic SDK generation system that automatically creates Software Development Kits (SDKs) for the X API from OpenAPI 3.0 specifications. The system is designed with extensibility and maintainability at its core, using a macro-driven approach to minimize boilerplate while maximizing consistency across different target languages. + +## Core Architecture + +```mermaid +graph TB + subgraph "Input" + OAS[OpenAPI 3.0 Specification] + end + + subgraph "XDK Core Libraries" + Parser[xdk-openapi
Parser & Reference Resolution] + Lib[xdk-lib
Models & Utilities] + Gen[xdk-gen
Language Generators] + Build[xdk-build
CLI Tool] + end + + subgraph "Language! Macro System" + Macro[language! macro] + Config[Language Configuration
• Casing Rules
• Template Filters
• Render Specs] + end + + subgraph "Processing Pipeline" + Extract[Extract Operations
Group by Tags] + Transform[Apply Casing
Transform Data Models] + Render[Render Templates
with Context] + end + + subgraph "Template System" + Templates[Jinja2 Templates
• models.j2
• client.j2
• tests.j2] + Filters[Template Filters
• Type Conversion
• Naming Helpers] + end + + subgraph "Output" + SDK[Generated SDK
• Client Libraries
• Data Models
• Test Suites] + Files[File Structure
• Language-specific layout
• Package metadata] + end + + OAS --> Parser + Parser --> Lib + Lib --> Extract + + Macro --> Config + Config --> Gen + Gen --> Transform + + Extract --> Transform + Transform --> Render + + Templates --> Render + Filters --> Render + + Render --> SDK + SDK --> Files + + Build --> Gen + + classDef input fill:#e1f5fe + classDef core fill:#f3e5f5 + classDef macro fill:#fff3e0 + classDef process fill:#e8f5e8 + classDef template fill:#fff8e1 + classDef output fill:#fce4ec + + class OAS input + class Parser,Lib,Gen,Build core + class Macro,Config macro + class Extract,Transform,Render process + class Templates,Filters template + class SDK,Files output +``` + +### 1. **Declarative Language Configuration** + +The heart of the XDK generator is the `language!` macro, which allows developers to declaratively define an entire SDK generator for any programming language in a single, concise specification: + +```rust +language! { + name: Python, + filters: [pascal_case, python_type, last_part], + class_casing: Casing::Pascal, + operation_casing: Casing::Snake, + import_casing: Casing::Snake, + variable_casing: Casing::Snake, + render: [ + multiple { + render "models" => "xdk/{}/models.py", + render "client_class" => "xdk/{}/client.py", + render "client_module" => "xdk/{}/__init__.py" + }, + render "main_client" => "xdk/client.py", + render "oauth2_auth" => "xdk/oauth2_auth.py", + render "init_py" => "xdk/__init__.py" + ], + tests: [ + multiple { + render "test_contracts" => "tests/{}/test_contracts.py", + render "test_structure" => "tests/{}/test_structure.py", + render "test_pagination" => "tests/{}/test_pagination.py" + }, + render "conftest" => "tests/conftest.py" + ] +} +``` + +This single declaration generates a complete, functional SDK generator that: +- Parses OpenAPI specifications +- Applies language-specific naming conventions +- Generates client libraries, models, and comprehensive test suites +- Handles complex scenarios like pagination, authentication, and error handling + +### 2. **Language-Agnostic Processing Pipeline** + +The XDK architecture separates concerns into distinct, reusable layers: + +#### **OpenAPI Parsing Layer** +- Custom OpenAPI 3.0 parser with lazy reference resolution +- Strongly-typed representation of API specifications +- Support for complex schemas, inheritance, and component references + +#### **Data Transformation Layer** +- Extracts operations, parameters, and schemas from OpenAPI specs +- Groups operations by tags for modular SDK organization +- Applies language-specific naming conventions consistently +- Generates comprehensive metadata for template rendering + +#### **Template Rendering Engine** +- MiniJinja-powered templating system +- Language-specific filters and helpers +- Context-aware rendering with rich data models +- Support for conditional logic and complex iterations + +#### **Test Generation System** +- Automatic generation of multiple test types: + - **Contract Tests**: Validate API compliance + - **Structure Tests**: Verify SDK interface correctness + - **Pagination Tests**: Handle paginated endpoints + - **Mock Scenarios**: Support offline development + +## Key Technical Innovations + +### 1. **Macro-Driven Code Generation** + +The `language!` macro is a Rust declarative macro that expands into a complete `LanguageGenerator` implementation. This approach provides several benefits: + +- **Zero Boilerplate**: Developers define behavior, not implementation +- **Compile-Time Validation**: Errors caught during compilation, not runtime +- **Consistent Architecture**: All generators follow the same patterns +- **Easy Maintenance**: Changes to the macro system benefit all languages + +### 2. **Intelligent Naming Convention System** + +The casing system automatically handles the complexities of cross-language naming: + +```rust +// Input: "getUserProfile" (from OpenAPI) +// Outputs: +// Python: get_user_profile (method), GetUserProfile (class) +// Java: getUserProfile (method), GetUserProfile (class) +// C#: GetUserProfile (method), GetUserProfile (class) +``` + +The system understands various input formats: +- camelCase (`getUserId`) +- PascalCase (`GetUserId`) +- snake_case (`get_user_id`) +- kebab-case (`get-user-id`) + +And converts them to any target convention with proper word boundary detection. + +### 3. **Unified Data Models** + +The system uses strongly-typed data structures that bridge the gap between OpenAPI specifications and target language requirements: + +```rust +pub struct OperationInfo { + pub class_name: String, // GetUserProfile + pub method_name: String, // get_user_profile + pub method: String, // GET + pub path: String, // /users/{id}/profile + pub parameters: Option>, + pub request_body: Option, + pub responses: HashMap, +} + +pub struct ParameterInfo { + pub original_name: String, // userId (from OpenAPI) + pub variable_name: String, // user_id (language-specific) + pub location: String, // path, query, header + pub required: bool, + pub param_type: String, + pub description: Option, +} +``` + +### 4. **Context-Rich Template System** + +Templates receive rich, pre-processed contexts that eliminate the need for complex template logic: + +```jinja2 +{% for operation in operations %} +class {{ operation.class_name }}: + def {{ operation.method_name }}(self, + {% for param in operation.parameters %} + {{ param.variable_name }}: {{ param.param_type }}, + {% endfor %} + ): + # Implementation +{% endfor %} +``` + +## End-to-End Generation Flow + +### Phase 1: **OpenAPI Analysis** +1. Parse OpenAPI specification into strongly-typed structures +2. Resolve all `$ref` references lazily as needed +3. Extract operations, grouping by tags for modular organization +4. Analyze parameters, request/response schemas, and security requirements + +### Phase 2: **Language-Specific Processing** +1. Apply naming conventions based on language configuration +2. Transform OpenAPI operations into language-specific data models +3. Generate test specifications with proper parameter casing +4. Create rich context objects for template rendering + +### Phase 3: **Code Generation** +1. Render main SDK files (clients, models) +2. Generate comprehensive test suites +3. Create package configuration files +4. Apply language-specific formatting and structure + +### Phase 4: **Output Organization** +1. Create appropriate directory structures +2. Write all generated files to target locations +3. Ensure proper file permissions and encoding +4. Generate package metadata and documentation + +## Extensibility Architecture + +### Adding New Languages + +Creating support for a new language requires only: + +1. **Language Configuration**: Define the `language!` macro call +2. **Template Creation**: Write Jinja2 templates for the target language +3. **Language-Specific Filters**: Add any custom template filters needed + +Example for adding Rust SDK generation: + +```rust +language! { + name: Rust, + filters: [rust_type, snake_case, pascal_case], + class_casing: Casing::Pascal, + operation_casing: Casing::Snake, + import_casing: Casing::Snake, + variable_casing: Casing::Snake, + render: [ + multiple { + render "models" => "src/{}/models.rs", + render "client" => "src/{}/client.rs", + }, + render "lib" => "src/lib.rs", + render "cargo_toml" => "Cargo.toml" + ], + tests: [ + multiple { + render "tests" => "tests/{}/mod.rs", + } + ] +} +``` + +### Template System Features + +Templates have access to powerful features: + +- **Language-Specific Filters**: Type conversion, naming conventions +- **Rich Context Objects**: Pre-processed data with all necessary information +- **Conditional Logic**: Handle optional parameters, different response types +- **Iteration Support**: Process collections of operations, parameters, schemas + +### Test Generation Framework + +The test generation system automatically creates: + +- **Contract Tests**: Verify API responses match OpenAPI specifications +- **Structure Tests**: Ensure SDK interfaces are correctly generated +- **Pagination Tests**: Handle APIs with cursor or offset-based pagination +- **Mock Scenarios**: Support offline development with realistic test data + + + +## Architecture Components + +### Core Libraries +- **xdk-openapi**: OpenAPI 3.0 parser with reference resolution +- **xdk-lib**: Shared utilities, models, and generation logic +- **xdk-gen**: Language-specific generators using the `language!` macro +- **xdk-build**: CLI tool for invoking generators + +### Data Flow +1. OpenAPI specification parsed into typed structures +2. Operations extracted and grouped by tags +3. Language-specific naming conventions applied +4. Templates rendered with processed contexts +5. Files written to output directory structure \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index c7b24af3..f3ea80e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -205,6 +205,12 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "displaydoc" version = "0.2.5" @@ -811,6 +817,16 @@ dependencies = [ "zerovec", ] +[[package]] +name = "pretty_assertions" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "proc-macro2" version = "1.0.95" @@ -1688,8 +1704,10 @@ version = "0.1.0" dependencies = [ "colored", "minijinja", + "pretty_assertions", "serde", "serde_json", + "tempfile", "thiserror", "xdk-openapi", ] @@ -1704,6 +1722,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "yoke" version = "0.8.0" diff --git a/Makefile b/Makefile index 4d814977..3946cbee 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,12 @@ # Default target: runs checks and tests all: check test +run-python: + cargo run -- python --latest true + +test-python: + cd xdk/python && uv run pytest tests/ + # Check formatting fmt: cargo fmt --all -- --check @@ -24,6 +30,9 @@ test: # Clean build artifacts clean: + rm -rf xdk/* + +cargo-clean: cargo clean -.PHONY: all fmt clippy check build test clean +.PHONY: all run-python test-python fmt clippy check build test clean cargo-clean diff --git a/xdk-gen/src/common/casing.rs b/xdk-gen/src/common/casing.rs deleted file mode 100644 index 28774fed..00000000 --- a/xdk-gen/src/common/casing.rs +++ /dev/null @@ -1,51 +0,0 @@ -/// MiniJinja filter for converting a string to snake_case -pub fn snake_case(value: &str) -> String { - let chars = value.chars(); - let mut result = String::new(); - let mut prev_is_underscore = false; - - for c in chars { - if c.is_uppercase() { - if !result.is_empty() && !prev_is_underscore { - result.push('_'); - } - result.push(c.to_ascii_lowercase()); - prev_is_underscore = false; - } else if c.is_alphanumeric() { - result.push(c.to_ascii_lowercase()); - prev_is_underscore = false; - } else if !prev_is_underscore { - result.push('_'); - prev_is_underscore = true; - } - } - - result.trim_matches('_').to_string() -} - -/// MiniJinja filter for converting a string to PascalCase -pub fn pascal_case(value: &str) -> String { - let mut result = String::new(); - let mut capitalize_next = true; - - for c in value.chars() { - if c == '_' || c == '-' || c == ' ' { - // Skip separators and capitalize the next character - capitalize_next = true; - } else if c.is_uppercase() { - // Uppercase letters indicate word boundaries - result.push(c); - capitalize_next = false; - } else if c.is_alphanumeric() { - if capitalize_next { - result.push(c.to_ascii_uppercase()); - capitalize_next = false; - } else { - result.push(c.to_ascii_lowercase()); - } - } - // Skip non-alphanumeric characters (except separators handled above) - } - - result -} diff --git a/xdk-gen/src/common/mod.rs b/xdk-gen/src/common/mod.rs deleted file mode 100644 index 309106ad..00000000 --- a/xdk-gen/src/common/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod casing; diff --git a/xdk-gen/src/lib.rs b/xdk-gen/src/lib.rs index b4c1d949..fb11790e 100644 --- a/xdk-gen/src/lib.rs +++ b/xdk-gen/src/lib.rs @@ -32,5 +32,4 @@ /// See the `python` module for a reference implementation of a language generator. pub use python::Python; -mod common; mod python; diff --git a/xdk-gen/src/python/generator.rs b/xdk-gen/src/python/generator.rs index 3217b946..ccd59f97 100644 --- a/xdk-gen/src/python/generator.rs +++ b/xdk-gen/src/python/generator.rs @@ -7,8 +7,7 @@ /// 1. Define language-specific filters (e.g., type conversion, naming conventions) /// 2. Use the language! macro to create the generator struct /// 3. Implement the rendering logic in the generate field -use crate::common::casing::{pascal_case, snake_case}; -use xdk_lib::language; +use xdk_lib::{Casing, language, pascal_case}; /// MiniJinja filter for converting to Python types fn python_type(value: &str) -> String { @@ -34,7 +33,11 @@ fn last_part(value: &str) -> String { */ language! { name: Python, - filters: [snake_case, pascal_case, python_type, last_part], + filters: [pascal_case, python_type, last_part], + class_casing: Casing::Pascal, + operation_casing: Casing::Snake, + import_casing: Casing::Snake, + variable_casing: Casing::Snake, render: [ multiple { render "models" => "xdk/{}/models.py", @@ -47,5 +50,14 @@ language! { render "init_py" => "xdk/__init__.py", render "pyproject_toml" => "pyproject.toml", render "readme" => "README.md" + ], + tests: [ + multiple { + render "test_contracts" => "tests/{}/test_contracts.py", + render "test_generic" => "tests/{}/test_generic.py", + render "test_structure" => "tests/{}/test_structure.py", + render "test_pagination" => "tests/{}/test_pagination.py" + }, + render "conftest" => "tests/conftest.py" ] } diff --git a/xdk-gen/templates/python/client_class.j2 b/xdk-gen/templates/python/client_class.j2 index dbe28a3b..7c7dbd6d 100644 --- a/xdk-gen/templates/python/client_class.j2 +++ b/xdk-gen/templates/python/client_class.j2 @@ -1,7 +1,7 @@ """ -{{ tag }} client for the X API. +{{ tag.display_name }} client for the X API. -This module provides a client for interacting with the {{ tag }} endpoints of the X API. +This module provides a client for interacting with the {{ tag.display_name }} endpoints of the X API. """ from __future__ import annotations @@ -14,45 +14,45 @@ if TYPE_CHECKING: from .models import ( {% for operation in operations %} {% if operation.request_body %} - {{ operation.operation_id | pascal_case }}Request, + {{ operation.class_name }}Request, {% if operation.responses and "200" in operation.responses or operation.responses and "201" in operation.responses %} - {{ operation.operation_id | pascal_case }}Response, + {{ operation.class_name }}Response, {% endif %} {% elif operation.responses and "200" in operation.responses or operation.responses and "201" in operation.responses %} - {{ operation.operation_id | pascal_case }}Response, + {{ operation.class_name }}Response, {% endif %} {% endfor %} ) -class {{ tag|pascal_case }}Client: - """Client for {{ tag }} operations""" +class {{ tag.class_name }}Client: + """Client for {{ tag.display_name }} operations""" def __init__(self, client: Client): self.client = client {% for operation in operations %} - def {{ operation.operation_id | snake_case }}(self, + def {{ operation.method_name }}(self, {# Required parameters #} {% for param in operation.parameters | selectattr('required') %} - {% if param.name %} - {{ param.name | snake_case }}: {% if param.schema and param.schema.type %}{{ param.schema.type | python_type }}{% else %}Any{% endif %}, + {% if param.original_name %} + {{ param.variable_name }}: {% if param.param_type %}{{ param.param_type | python_type }}{% else %}Any{% endif %}, {% endif %} {% endfor %} {# Required body #} {% if operation.request_body and operation.request_body.required %} - body: {{ operation.operation_id | pascal_case }}Request, + body: {{ operation.class_name }}Request, {% endif %} {# Optional parameters #} {% for param in operation.parameters | rejectattr('required') %} - {% if param.name %} - {{ param.name | snake_case }}: {% if param.schema and param.schema.type %}{{ param.schema.type | python_type }}{% else %}Any{% endif %} = None, + {% if param.original_name %} + {{ param.variable_name }}: {% if param.param_type %}{{ param.param_type | python_type }}{% else %}Any{% endif %} = None, {% endif %} {% endfor %} {# Optional body #} {% if operation.request_body and not operation.request_body.required %} - body: Optional[{{ operation.operation_id | pascal_case }}Request] = None, + body: Optional[{{ operation.class_name }}Request] = None, {% endif %} - ) -> {% if operation.responses and "200" in operation.responses %}{{ operation.operation_id | pascal_case }}Response{% else %}Dict[str, Any]{% endif %}: + ) -> {% if operation.responses and "200" in operation.responses %}{{ operation.class_name }}Response{% else %}Dict[str, Any]{% endif %}: """ {{ operation.summary | default("") }} @@ -61,9 +61,9 @@ class {{ tag|pascal_case }}Client: {% endif %} {% for param in operation.parameters %} - {% if param.name %} + {% if param.original_name %} Args: - {{ param.name | snake_case }}: {% if param.description %}{{ param.description }}{% else %}{{ param.name }}{% endif %} + {{ param.variable_name }}: {% if param.description %}{{ param.description }}{% else %}{{ param.original_name }}{% endif %} {% endif %} {% endfor %} {% if operation.request_body %} @@ -81,7 +81,7 @@ class {{ tag|pascal_case }}Client: {% endif %} Returns: - {% if operation.responses and "200" in operation.responses or "201" in operation.responses %}{{ operation.operation_id | pascal_case }}Response{% else %}Dict[str, Any]{% endif %}: Response data + {% if operation.responses and "200" in operation.responses or "201" in operation.responses %}{{ operation.class_name }}Response{% else %}Dict[str, Any]{% endif %}: Response data """ url = self.client.base_url + "{{ operation.path }}" @@ -111,33 +111,27 @@ class {{ tag|pascal_case }}Client: params = {} {% for param in operation.parameters %} - {% if param.name %} - {% if param.in == "query" %} - if {{ param.name | snake_case }} is not None: - {% if param.schema and param.schema.type == "array" and not param.explode %} - params["{{ param.name }}"] = ",".join(str(item) for item in {{ param.name | snake_case }}) + {% if param.location == "query" %} + if {{ param.variable_name }} is not None: + {% if param.param_type == "array" %} + params["{{ param.original_name }}"] = ",".join(str(item) for item in {{ param.variable_name }}) {% else %} - params["{{ param.name }}"] = {{ param.name | snake_case }} + params["{{ param.original_name }}"] = {{ param.variable_name }} {% endif %} {% endif %} - {% endif %} {% endfor %} {% for param in operation.parameters %} - {% if param.name %} - {% if param.in == "path" %} - url = url.replace("{{ '{' + param.name + '}' }}", str({{ param.name | snake_case }})) - {% endif %} + {% if param.location == "path" %} + url = url.replace("{{ '{' + param.original_name + '}' }}", str({{ param.variable_name }})) {% endif %} {% endfor %} headers = {} {% for param in operation.parameters %} - {% if param.name %} - {% if param.in == "header" %} - if {{ param.name | snake_case }} is not None: - headers["{{ param.name }}"] = {{ param.name | snake_case }} - {% endif %} + {% if param.location == "header" %} + if {{ param.variable_name }} is not None: + headers["{{ param.original_name }}"] = {{ param.variable_name }} {% endif %} {% endfor %} {% if operation.request_body and operation.request_body.content %} @@ -205,7 +199,7 @@ class {{ tag|pascal_case }}Client: # Convert to Pydantic model if applicable {% if operation.responses and "200" in operation.responses or operation.responses and "201" in operation.responses %} - return {{ operation.operation_id | pascal_case }}Response.model_validate(response_data) + return {{ operation.class_name }}Response.model_validate(response_data) {% else %} return response_data {% endif %} diff --git a/xdk-gen/templates/python/client_module.j2 b/xdk-gen/templates/python/client_module.j2 index 165b98e3..f2ed8c61 100644 --- a/xdk-gen/templates/python/client_module.j2 +++ b/xdk-gen/templates/python/client_module.j2 @@ -1,9 +1,9 @@ """ -{{ tag }} module for the X API. +{{ tag.display_name }} module for the X API. -This module provides access to the {{ tag }} endpoints of the X API. +This module provides access to the {{ tag.display_name }} endpoints of the X API. """ -from .client import {{ tag|pascal_case }}Client +from .client import {{ tag.class_name }}Client -__all__ = ["{{ tag|pascal_case }}Client"] \ No newline at end of file +__all__ = ["{{ tag.class_name }}Client"] \ No newline at end of file diff --git a/xdk-gen/templates/python/main_client.j2 b/xdk-gen/templates/python/main_client.j2 index 1d9e1945..5b4587f2 100644 --- a/xdk-gen/templates/python/main_client.j2 +++ b/xdk-gen/templates/python/main_client.j2 @@ -10,7 +10,7 @@ from typing import Dict, List, Optional, Union, Any, Callable from .oauth2_auth import OAuth2PKCEAuth from .paginator import Cursor, cursor, PaginationError {% for tag in tags %} -from .{{ tag|replace(" ", "_")|lower }}.client import {{ tag|pascal_case }}Client +from .{{ tag.import_name }}.client import {{ tag.class_name }}Client {% endfor %} @@ -54,7 +54,7 @@ class Client: # Initialize clients for each tag {% for tag in tags %} - self.{{ tag|replace(" ", "_")|lower }} = {{ tag|pascal_case }}Client(self) + self.{{ tag.property_name }} = {{ tag.class_name }}Client(self) {% endfor %} @property diff --git a/xdk-gen/templates/python/models.j2 b/xdk-gen/templates/python/models.j2 index c4bc74db..7b8aa3ca 100644 --- a/xdk-gen/templates/python/models.j2 +++ b/xdk-gen/templates/python/models.j2 @@ -1,7 +1,7 @@ """ -{{ tag }} models for the X API. +{{ tag.display_name }} models for the X API. -This module provides models for the {{ tag }} endpoints of the X API. +This module provides models for the {{ tag.display_name }} endpoints of the X API. """ from typing import Dict, List, Optional, Any, Union, Literal @@ -49,10 +49,10 @@ Any {% for operation in operations %} {% if operation.request_body or operation.responses %} -# Models for {{ operation.operation_id }} +# Models for {{ operation.method_name }} {% if operation.request_body %} -class {{ operation.operation_id | pascal_case }}Request(BaseModel): - """Request model for {{ operation.operation_id }}""" +class {{ operation.class_name }}Request(BaseModel): + """Request model for {{ operation.method_name }}""" {%- if operation.request_body.content %} {%- set content_type = "application/json" %} {%- if operation.request_body.content[content_type] %} @@ -62,7 +62,7 @@ class {{ operation.operation_id | pascal_case }}Request(BaseModel): {%- if schema.properties %} {%- for key in schema.properties %} {%- set prop = schema.properties[key] %} - {{ key }}: {{ field_type(prop, operation.operation_id | pascal_case + "Request", key) }} = {%- if not prop.required %}None{%- else %}Field({%- if prop.description %}description="{{ prop.description }}", {%- endif %}{%- if prop.default %}default={{ prop.default }}{%- elif prop.type == 'array' %}default_factory=list{%- elif prop.type == 'object' %}default_factory=dict{%- else %}...{%- endif %}){%- endif %} + {{ key }}: {{ field_type(prop, operation.class_name + "Request", key) }} = {%- if not prop.required %}None{%- else %}Field({%- if prop.description %}description="{{ prop.description }}", {%- endif %}{%- if prop.default %}default={{ prop.default }}{%- elif prop.type == 'array' %}default_factory=list{%- elif prop.type == 'object' %}default_factory=dict{%- else %}...{%- endif %}){%- endif %} {%- endfor %} {# Handle anyOf composition schemas #} {%- elif schema.anyOf %} @@ -111,14 +111,14 @@ class {{ operation.operation_id | pascal_case }}Request(BaseModel): {% set content_type = "application/json" %} {% if response.content[content_type] %} {% set schema = response.content[content_type].schema %} -class {{ operation.operation_id | pascal_case }}Response(BaseModel): - """Response model for {{ operation.operation_id }}""" +class {{ operation.class_name }}Response(BaseModel): + """Response model for {{ operation.method_name }}""" {%- if schema %} {# Handle regular object schemas with properties #} {%- if schema.properties %} {%- for key in schema.properties %} {%- set prop = schema.properties[key] %} - {{ key }}: {{ field_type(prop, operation.operation_id | pascal_case + "Response", key) }} = {%- if not prop.required %}None{%- else %}Field({%- if prop.description %}description="{{ prop.description }}", {%- endif %}{%- if prop.default %}default={{ prop.default }}{%- elif prop.type == 'array' %}default_factory=list{%- elif prop.type == 'object' %}default_factory=dict{%- else %}...{%- endif %}){%- endif %} + {{ key }}: {{ field_type(prop, operation.class_name + "Response", key) }} = {%- if not prop.required %}None{%- else %}Field({%- if prop.description %}description="{{ prop.description }}", {%- endif %}{%- if prop.default %}default={{ prop.default }}{%- elif prop.type == 'array' %}default_factory=list{%- elif prop.type == 'object' %}default_factory=dict{%- else %}...{%- endif %}){%- endif %} {%- endfor %} {# Handle anyOf composition schemas #} {%- elif schema.anyOf %} @@ -170,7 +170,7 @@ class {{ operation.operation_id | pascal_case }}Response(BaseModel): {% for key in schema.properties %} {% set prop = schema.properties[key] %} {% if prop.type == 'object' and prop.properties %} -{{ generate_nested_class(operation.operation_id | pascal_case + "Request" + key | pascal_case, prop) }} +{{ generate_nested_class(operation.class_name + "Request" + key | pascal_case, prop) }} {% endif %} {% endfor %} {% endif %} @@ -188,7 +188,7 @@ class {{ operation.operation_id | pascal_case }}Response(BaseModel): {% for key in schema.properties %} {% set prop = schema.properties[key] %} {% if prop.type == 'object' and prop.properties %} -{{ generate_nested_class(operation.operation_id | pascal_case + "Response" + key | pascal_case, prop) }} +{{ generate_nested_class(operation.class_name + "Response" + key | pascal_case, prop) }} {% endif %} {% endfor %} {% endif %} diff --git a/xdk-gen/templates/python/paginator.j2 b/xdk-gen/templates/python/paginator.j2 index 9208fc9e..7e29f087 100644 --- a/xdk-gen/templates/python/paginator.j2 +++ b/xdk-gen/templates/python/paginator.j2 @@ -65,9 +65,9 @@ class Cursor(Generic[ResponseType]): print(user.name) # For methods with query parameters - cursor = Cursor(client.tweets.search_posts_recent, "python", max_results=50) + cursor = Cursor(client.posts.search_posts_recent, "python", max_results=50) for page in cursor.pages(5): # page is SearchResponse type - print(f"Got {len(page.data)} tweets") + print(f"Got {len(page.data)} posts") """ def __init__(self, method: PaginatableMethod[ResponseType], *args: Any, **kwargs: Any): @@ -147,7 +147,7 @@ def cursor(method: PaginatableMethod[ResponseType], *args: Any, **kwargs: Any) - print(len(page.data)) # For search methods - search_cursor = cursor(client.tweets.search_posts_recent, "python", max_results=50) + search_cursor = cursor(client.posts.search_posts_recent, "python", max_results=50) for tweet in search_cursor.items(100): print(tweet.text) """ diff --git a/xdk-gen/templates/python/readme.j2 b/xdk-gen/templates/python/readme.j2 index 54ccd05f..725eb9c1 100644 --- a/xdk-gen/templates/python/readme.j2 +++ b/xdk-gen/templates/python/readme.j2 @@ -27,14 +27,14 @@ client = Client( ) # Use the client to interact with the X API -# For example, to get tweets: -tweets = client.tweets.get_tweets(ids=["1234567890"]) +# For example, to get posts: +posts = client.posts.get(ids=["1234567890"]) -# To search for tweets: -search_results = client.tweets.tweets_recent_search(query="python") +# To search for posts: +search_results = client.posts.recent_search(query="python") -# To post a tweet: -tweet = client.tweets.post_tweets(tweet_data={"text": "Hello, world!"}) +# To post a post: +post = client.posts.create(post_data={"text": "Hello, world!"}) ``` ## Features diff --git a/xdk-gen/templates/python/test_contracts.j2 b/xdk-gen/templates/python/test_contracts.j2 index 70394a23..95eb5f4b 100644 --- a/xdk-gen/templates/python/test_contracts.j2 +++ b/xdk-gen/templates/python/test_contracts.j2 @@ -10,21 +10,21 @@ Generated automatically - do not edit manually. import pytest import json from unittest.mock import Mock, patch -from xdk.{{ tag|lower }}.client import {{ tag|pascal_case }}Client +from xdk.{{ tag.import_name }}.client import {{ tag.class_name }}Client from xdk import Client -class Test{{ tag|pascal_case }}Contracts: - """Test the API contracts of {{ tag|pascal_case }}Client.""" +class Test{{ tag.class_name }}Contracts: + """Test the API contracts of {{ tag.class_name }}Client.""" def setup_class(self): """Set up test fixtures.""" self.client = Client(base_url="https://api.example.com") - self.{{ tag|lower }}_client = getattr(self.client, "{{ tag|lower }}") + self.{{ tag.property_name }}_client = getattr(self.client, "{{ tag.property_name }}") {% for contract_test in test_spec.contract_tests %} - def test_{{ contract_test.operation_id|snake_case }}_request_structure(self): - """Test {{ contract_test.operation_id|snake_case }} request structure.""" + def test_{{ contract_test.method_name }}_request_structure(self): + """Test {{ contract_test.method_name }} request structure.""" # Mock the session to capture request details with patch.object(self.client, 'session') as mock_session: @@ -69,14 +69,14 @@ class Test{{ tag|pascal_case }}Contracts: # Add request body if required {% if contract_test.request_body_schema %} # Import and create proper request model instance - from xdk.{{ tag|lower }}.models import {{ contract_test.operation_id|pascal_case }}Request + from xdk.{{ tag.property_name }}.models import {{ contract_test.class_name }}Request # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = {{ contract_test.operation_id|pascal_case }}Request() + kwargs["body"] = {{ contract_test.class_name }}Request() {% endif %} # Call the method try: - method = getattr(self.{{ tag|lower }}_client, "{{ contract_test.operation_id|snake_case }}") + method = getattr(self.{{ tag.property_name }}_client, "{{ contract_test.method_name }}") result = method(**kwargs) # Verify the request was made @@ -96,11 +96,11 @@ class Test{{ tag|pascal_case }}Contracts: assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for {{ contract_test.operation_id|snake_case }}: {e}") + pytest.fail(f"Contract test failed for {{ contract_test.method_name }}: {e}") - def test_{{ contract_test.operation_id|snake_case }}_required_parameters(self): - """Test that {{ contract_test.operation_id|snake_case }} handles parameters correctly.""" - method = getattr(self.{{ tag|lower }}_client, "{{ contract_test.operation_id|snake_case }}") + def test_{{ contract_test.method_name }}_required_parameters(self): + """Test that {{ contract_test.method_name }} handles parameters correctly.""" + method = getattr(self.{{ tag.property_name }}_client, "{{ contract_test.method_name }}") {% if contract_test.required_params or contract_test.request_body_schema %} # Test with missing required parameters - mock the request to avoid network calls @@ -130,8 +130,8 @@ class Test{{ tag|pascal_case }}Contracts: pytest.fail(f"Method with no required params should be callable: {e}") {% endif %} - def test_{{ contract_test.operation_id|snake_case }}_response_structure(self): - """Test {{ contract_test.operation_id|snake_case }} response structure validation.""" + def test_{{ contract_test.method_name }}_response_structure(self): + """Test {{ contract_test.method_name }} response structure validation.""" with patch.object(self.client, 'session') as mock_session: # Create mock response with expected structure @@ -186,13 +186,13 @@ class Test{{ tag|pascal_case }}Contracts: # Add request body if required {% if contract_test.request_body_schema %} # Import and create proper request model instance - from xdk.{{ tag|lower }}.models import {{ contract_test.operation_id|pascal_case }}Request + from xdk.{{ tag.property_name }}.models import {{ contract_test.class_name }}Request # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = {{ contract_test.operation_id|pascal_case }}Request() + kwargs["body"] = {{ contract_test.class_name }}Request() {% endif %} # Call method and verify response structure - method = getattr(self.{{ tag|lower }}_client, "{{ contract_test.operation_id|snake_case }}") + method = getattr(self.{{ tag.property_name }}_client, "{{ contract_test.method_name }}") result = method(**kwargs) # Verify response object has expected attributes diff --git a/xdk-gen/templates/python/test_generic.j2 b/xdk-gen/templates/python/test_generic.j2 index b72a68ec..cddfe507 100644 --- a/xdk-gen/templates/python/test_generic.j2 +++ b/xdk-gen/templates/python/test_generic.j2 @@ -11,28 +11,28 @@ Generated automatically - do not edit manually. import pytest import inspect from unittest.mock import Mock, patch -from xdk.{{ tag|lower }}.client import {{ tag|pascal_case }}Client +from xdk.{{ tag.import_name }}.client import {{ tag.class_name }}Client from xdk import Client -class Test{{ tag|pascal_case }}Generic: - """Generic tests for {{ tag|pascal_case }}Client.""" +class Test{{ tag.class_name }}Generic: + """Generic tests for {{ tag.class_name }}Client.""" def setup_class(self): """Set up test fixtures.""" self.client = Client(base_url="https://api.example.com") - self.{{ tag|lower }}_client = getattr(self.client, "{{ tag|lower }}") + self.{{ tag.property_name }}_client = getattr(self.client, "{{ tag.property_name }}") def test_client_exists(self): - """Test that {{ tag|pascal_case }}Client class exists and is importable.""" - assert {{ tag|pascal_case }}Client is not None - assert hasattr({{ tag|pascal_case }}Client, '__name__') - assert {{ tag|pascal_case }}Client.__name__ == "{{ tag|pascal_case }}Client" + """Test that {{ tag.class_name }}Client class exists and is importable.""" + assert {{ tag.class_name }}Client is not None + assert hasattr({{ tag.class_name }}Client, '__name__') + assert {{ tag.class_name }}Client.__name__ == "{{ tag.class_name }}Client" def test_client_initialization(self): - """Test that {{ tag|pascal_case }}Client can be initialized properly.""" - assert self.{{ tag|lower }}_client is not None - assert isinstance(self.{{ tag|lower }}_client, {{ tag|pascal_case }}Client) + """Test that {{ tag.class_name }}Client can be initialized properly.""" + assert self.{{ tag.property_name }}_client is not None + assert isinstance(self.{{ tag.property_name }}_client, {{ tag.class_name }}Client) def test_imports_work(self): """Test that all expected imports work correctly.""" @@ -62,12 +62,12 @@ class Test{{ tag|pascal_case }}Generic: mock_session.delete.return_value = mock_response # Get first available method for testing error handling - client_methods = [name for name in dir({{ tag|pascal_case }}Client) - if not name.startswith('_') and callable(getattr({{ tag|pascal_case }}Client, name))] + client_methods = [name for name in dir({{ tag.class_name }}Client) + if not name.startswith('_') and callable(getattr({{ tag.class_name }}Client, name))] if client_methods: method_name = client_methods[0] - method = getattr(self.{{ tag|lower }}_client, method_name) + method = getattr(self.{{ tag.property_name }}_client, method_name) # Try calling the method and expect an exception with pytest.raises(Exception): @@ -85,24 +85,24 @@ class Test{{ tag|pascal_case }}Generic: def test_client_has_expected_base_functionality(self): """Test that the client has expected base functionality.""" # Should be able to access the client through main Client - assert hasattr(self.client, "{{ tag|lower }}") + assert hasattr(self.client, "{{ tag.property_name }}") # Client should have standard Python object features - assert hasattr(self.{{ tag|lower }}_client, '__class__') - assert hasattr(self.{{ tag|lower }}_client, '__dict__') + assert hasattr(self.{{ tag.property_name }}_client, '__class__') + assert hasattr(self.{{ tag.property_name }}_client, '__dict__') # Should have at least one public method - public_methods = [name for name in dir(self.{{ tag|lower }}_client) - if not name.startswith('_') and callable(getattr(self.{{ tag|lower }}_client, name))] - assert len(public_methods) > 0, f"{{ tag|pascal_case }}Client should have at least one public method" + public_methods = [name for name in dir(self.{{ tag.property_name }}_client) + if not name.startswith('_') and callable(getattr(self.{{ tag.property_name }}_client, name))] + assert len(public_methods) > 0, f"{{ tag.class_name }}Client should have at least one public method" def test_client_method_signatures_are_valid(self): """Test that all client methods have valid Python signatures.""" - public_methods = [name for name in dir({{ tag|pascal_case }}Client) - if not name.startswith('_') and callable(getattr({{ tag|pascal_case }}Client, name))] + public_methods = [name for name in dir({{ tag.class_name }}Client) + if not name.startswith('_') and callable(getattr({{ tag.class_name }}Client, name))] for method_name in public_methods: - method = getattr({{ tag|pascal_case }}Client, method_name) + method = getattr({{ tag.class_name }}Client, method_name) # Should be able to get signature without error try: diff --git a/xdk-gen/templates/python/test_pagination.j2 b/xdk-gen/templates/python/test_pagination.j2 index b5dc565d..08d13bfc 100644 --- a/xdk-gen/templates/python/test_pagination.j2 +++ b/xdk-gen/templates/python/test_pagination.j2 @@ -9,34 +9,34 @@ Generated automatically - do not edit manually. import pytest from unittest.mock import Mock, patch -from xdk.{{ tag|lower }}.client import {{ tag|pascal_case }}Client +from xdk.{{ tag.import_name }}.client import {{ tag.class_name }}Client from xdk import Client, Cursor, cursor, PaginationError -class Test{{ tag|pascal_case }}Pagination: - """Test pagination functionality for {{ tag|pascal_case }}Client.""" +class Test{{ tag.class_name }}Pagination: + """Test pagination functionality for {{ tag.class_name }}Client.""" def setup_class(self): """Set up test fixtures.""" self.client = Client(base_url="https://api.example.com") - self.{{ tag|lower }}_client = getattr(self.client, "{{ tag|lower }}") + self.{{ tag.property_name }}_client = getattr(self.client, "{{ tag.property_name }}") {% for pagination_test in test_spec.pagination_tests %} - def test_{{ pagination_test.method_name|snake_case }}_cursor_creation(self): - """Test that {{ pagination_test.method_name|snake_case }} can be used with Cursor.""" - method = getattr(self.{{ tag|lower }}_client, "{{ pagination_test.method_name|snake_case }}") + def test_{{ pagination_test.method_name }}_cursor_creation(self): + """Test that {{ pagination_test.method_name }} can be used with Cursor.""" + method = getattr(self.{{ tag.property_name }}_client, "{{ pagination_test.method_name }}") # Should be able to create cursor without error try: - test_cursor = cursor(method{% for param in pagination_test.required_params %}{% if param.param_type == "string" %}{% if "query" in param.name|snake_case %}, "test_query"{% elif "id" in param.name|snake_case %}, "test_id"{% elif "participant" in param.name|snake_case %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% elif param.param_type == "boolean" %}, {{ param.name }}=True{% elif param.param_type == "integer" %}, {{ param.name }}=1{% elif param.param_type == "reference" %}{% if "query" in param.name|snake_case %}, "test_query"{% elif "id" in param.name|snake_case %}, "test_id"{% elif "participant" in param.name|snake_case %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% else %}, "test_value"{% endif %}{% endfor %}, max_results=10) + test_cursor = cursor(method{% for param in pagination_test.required_params %}{% if param.param_type == "string" %}{% if "query" in param.variable_name %}, "test_query"{% elif "id" in param.variable_name %}, "test_id"{% elif "participant" in param.variable_name %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% elif param.param_type == "boolean" %}, {{ param.name }}=True{% elif param.param_type == "integer" %}, {{ param.name }}=1{% elif param.param_type == "reference" %}{% if "query" in param.variable_name %}, "test_query"{% elif "id" in param.variable_name %}, "test_id"{% elif "participant" in param.variable_name %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% else %}, "test_value"{% endif %}{% endfor %}, max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method {{ pagination_test.operation_id }} should support pagination") + pytest.fail(f"Method {{ pagination_test.method_name }} should support pagination") - def test_{{ pagination_test.method_name|snake_case }}_cursor_pages(self): - """Test pagination with pages() for {{ pagination_test.method_name|snake_case }}.""" + def test_{{ pagination_test.method_name }}_cursor_pages(self): + """Test pagination with pages() for {{ pagination_test.method_name }}.""" with patch.object(self.client, 'session') as mock_session: # Mock first page response @@ -73,8 +73,8 @@ class Test{{ tag|pascal_case }}Pagination: mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.{{ tag|lower }}_client, "{{ pagination_test.method_name|snake_case }}") - test_cursor = cursor(method{% for param in pagination_test.required_params %}{% if param.param_type == "string" %}{% if "query" in param.name|snake_case %}, "test_query"{% elif "id" in param.name|snake_case %}, "test_id"{% elif "participant" in param.name|snake_case %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% elif param.param_type == "boolean" %}, {{ param.name }}=True{% elif param.param_type == "integer" %}, {{ param.name }}=1{% elif param.param_type == "reference" %}{% if "query" in param.name|snake_case %}, "test_query"{% elif "id" in param.name|snake_case %}, "test_id"{% elif "participant" in param.name|snake_case %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% else %}, "test_value"{% endif %}{% endfor %}, max_results=2) + method = getattr(self.{{ tag.property_name }}_client, "{{ pagination_test.method_name }}") + test_cursor = cursor(method{% for param in pagination_test.required_params %}{% if param.param_type == "string" %}{% if "query" in param.variable_name %}, "test_query"{% elif "id" in param.variable_name %}, "test_id"{% elif "participant" in param.variable_name %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% elif param.param_type == "boolean" %}, {{ param.name }}=True{% elif param.param_type == "integer" %}, {{ param.name }}=1{% elif param.param_type == "reference" %}{% if "query" in param.variable_name %}, "test_query"{% elif "id" in param.variable_name %}, "test_id"{% elif "participant" in param.variable_name %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% else %}, "test_value"{% endif %}{% endfor %}, max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages @@ -92,8 +92,8 @@ class Test{{ tag|pascal_case }}Pagination: second_data = getattr(second_page, "{{ pagination_test.data_field }}") assert len(second_data) == 1, "Second page should have 1 item" - def test_{{ pagination_test.method_name|snake_case }}_cursor_items(self): - """Test pagination with items() for {{ pagination_test.method_name|snake_case }}.""" + def test_{{ pagination_test.method_name }}_cursor_items(self): + """Test pagination with items() for {{ pagination_test.method_name }}.""" with patch.object(self.client, 'session') as mock_session: # Mock response with paginated data @@ -114,8 +114,8 @@ class Test{{ tag|pascal_case }}Pagination: mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.{{ tag|lower }}_client, "{{ pagination_test.method_name|snake_case }}") - test_cursor = cursor(method{% for param in pagination_test.required_params %}{% if param.param_type == "string" %}{% if "query" in param.name|snake_case %}, "test_query"{% elif "id" in param.name|snake_case %}, "test_id"{% elif "participant" in param.name|snake_case %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% elif param.param_type == "boolean" %}, {{ param.name }}=True{% elif param.param_type == "integer" %}, {{ param.name }}=1{% elif param.param_type == "reference" %}{% if "query" in param.name|snake_case %}, "test_query"{% elif "id" in param.name|snake_case %}, "test_id"{% elif "participant" in param.name|snake_case %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% else %}, "test_value"{% endif %}{% endfor %}, max_results=10) + method = getattr(self.{{ tag.property_name }}_client, "{{ pagination_test.method_name }}") + test_cursor = cursor(method{% for param in pagination_test.required_params %}{% if param.param_type == "string" %}{% if "query" in param.variable_name %}, "test_query"{% elif "id" in param.variable_name %}, "test_id"{% elif "participant" in param.variable_name %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% elif param.param_type == "boolean" %}, {{ param.name }}=True{% elif param.param_type == "integer" %}, {{ param.name }}=1{% elif param.param_type == "reference" %}{% if "query" in param.variable_name %}, "test_query"{% elif "id" in param.variable_name %}, "test_id"{% elif "participant" in param.variable_name %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% else %}, "test_value"{% endif %}{% endfor %}, max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items @@ -125,8 +125,8 @@ class Test{{ tag|pascal_case }}Pagination: for item in items: assert "id" in item or hasattr(item, "id"), "Items should have 'id' field" - def test_{{ pagination_test.method_name|snake_case }}_pagination_parameters(self): - """Test that pagination parameters are handled correctly for {{ pagination_test.method_name|snake_case }}.""" + def test_{{ pagination_test.method_name }}_pagination_parameters(self): + """Test that pagination parameters are handled correctly for {{ pagination_test.method_name }}.""" with patch.object(self.client, 'session') as mock_session: mock_response = Mock() @@ -138,11 +138,11 @@ class Test{{ tag|pascal_case }}Pagination: mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.{{ tag|lower }}_client, "{{ pagination_test.method_name|snake_case }}") + method = getattr(self.{{ tag.property_name }}_client, "{{ pagination_test.method_name }}") # Test with max_results parameter {% if pagination_test.max_results_param %} - test_cursor = cursor(method{% for param in pagination_test.required_params %}{% if param.param_type == "string" %}{% if "query" in param.name|snake_case %}, "test_query"{% elif "id" in param.name|snake_case %}, "test_id"{% elif "participant" in param.name|snake_case %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% elif param.param_type == "boolean" %}, {{ param.name }}=True{% elif param.param_type == "integer" %}, {{ param.name }}=1{% elif param.param_type == "reference" %}{% if "query" in param.name|snake_case %}, "test_query"{% elif "id" in param.name|snake_case %}, "test_id"{% elif "participant" in param.name|snake_case %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% else %}, "test_value"{% endif %}{% endfor %}, {{ pagination_test.max_results_param }}=5) + test_cursor = cursor(method{% for param in pagination_test.required_params %}{% if param.param_type == "string" %}{% if "query" in param.variable_name %}, "test_query"{% elif "id" in param.variable_name %}, "test_id"{% elif "participant" in param.variable_name %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% elif param.param_type == "boolean" %}, {{ param.name }}=True{% elif param.param_type == "integer" %}, {{ param.name }}=1{% elif param.param_type == "reference" %}{% if "query" in param.variable_name %}, "test_query"{% elif "id" in param.variable_name %}, "test_id"{% elif "participant" in param.variable_name %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% else %}, "test_value"{% endif %}{% endfor %}, {{ pagination_test.max_results_param }}=5) list(test_cursor.pages(1)) # Trigger one request # Verify max_results was passed in request @@ -152,7 +152,7 @@ class Test{{ tag|pascal_case }}Pagination: assert "{{ pagination_test.max_results_param }}" in params, \ "{{ pagination_test.max_results_param }} should be in request parameters" {% else %} - test_cursor = cursor(method{% for param in pagination_test.required_params %}{% if param.param_type == "string" %}{% if "query" in param.name|snake_case %}, "test_query"{% elif "id" in param.name|snake_case %}, "test_id"{% elif "participant" in param.name|snake_case %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% elif param.param_type == "boolean" %}, {{ param.name }}=True{% elif param.param_type == "integer" %}, {{ param.name }}=1{% elif param.param_type == "reference" %}{% if "query" in param.name|snake_case %}, "test_query"{% elif "id" in param.name|snake_case %}, "test_id"{% elif "participant" in param.name|snake_case %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% else %}, "test_value"{% endif %}{% endfor %}, max_results=5) + test_cursor = cursor(method{% for param in pagination_test.required_params %}{% if param.param_type == "string" %}{% if "query" in param.variable_name %}, "test_query"{% elif "id" in param.variable_name %}, "test_id"{% elif "participant" in param.variable_name %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% elif param.param_type == "boolean" %}, {{ param.name }}=True{% elif param.param_type == "integer" %}, {{ param.name }}=1{% elif param.param_type == "reference" %}{% if "query" in param.variable_name %}, "test_query"{% elif "id" in param.variable_name %}, "test_id"{% elif "participant" in param.variable_name %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% else %}, "test_value"{% endif %}{% endfor %}, max_results=5) list(test_cursor.pages(1)) # Trigger one request # Verify max_results was passed in request @@ -186,7 +186,7 @@ class Test{{ tag|pascal_case }}Pagination: mock_session.get.side_effect = [mock_response_with_token, second_page_response] - test_cursor = cursor(method{% for param in pagination_test.required_params %}{% if param.param_type == "string" %}{% if "query" in param.name|snake_case %}, "test_query"{% elif "id" in param.name|snake_case %}, "test_id"{% elif "participant" in param.name|snake_case %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% elif param.param_type == "boolean" %}, {{ param.name }}=True{% elif param.param_type == "integer" %}, {{ param.name }}=1{% elif param.param_type == "reference" %}{% if "query" in param.name|snake_case %}, "test_query"{% elif "id" in param.name|snake_case %}, "test_id"{% elif "participant" in param.name|snake_case %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% else %}, "test_value"{% endif %}{% endfor %}, max_results=1) + test_cursor = cursor(method{% for param in pagination_test.required_params %}{% if param.param_type == "string" %}{% if "query" in param.variable_name %}, "test_query"{% elif "id" in param.variable_name %}, "test_id"{% elif "participant" in param.variable_name %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% elif param.param_type == "boolean" %}, {{ param.name }}=True{% elif param.param_type == "integer" %}, {{ param.name }}=1{% elif param.param_type == "reference" %}{% if "query" in param.variable_name %}, "test_query"{% elif "id" in param.variable_name %}, "test_id"{% elif "participant" in param.variable_name %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% else %}, "test_value"{% endif %}{% endfor %}, max_results=1) pages = list(test_cursor.pages(2)) # Should have made 2 requests @@ -218,8 +218,8 @@ class Test{{ tag|pascal_case }}Pagination: # Pick first paginatable method for testing {% if test_spec.pagination_tests %} {% set pagination_test = test_spec.pagination_tests[0] %} - method = getattr(self.{{ tag|lower }}_client, "{{ pagination_test.method_name|snake_case }}") - test_cursor = cursor(method{% for param in pagination_test.required_params %}{% if param.param_type == "string" %}{% if "query" in param.name|snake_case %}, "test_query"{% elif "id" in param.name|snake_case %}, "test_id"{% elif "participant" in param.name|snake_case %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% elif param.param_type == "boolean" %}, {{ param.name }}=True{% elif param.param_type == "integer" %}, {{ param.name }}=1{% elif param.param_type == "reference" %}{% if "query" in param.name|snake_case %}, "test_query"{% elif "id" in param.name|snake_case %}, "test_id"{% elif "participant" in param.name|snake_case %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% else %}, "test_value"{% endif %}{% endfor %}, max_results=10) + method = getattr(self.{{ tag.property_name }}_client, "{{ pagination_test.method_name }}") + test_cursor = cursor(method{% for param in pagination_test.required_params %}{% if param.param_type == "string" %}{% if "query" in param.variable_name %}, "test_query"{% elif "id" in param.variable_name %}, "test_id"{% elif "participant" in param.variable_name %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% elif param.param_type == "boolean" %}, {{ param.name }}=True{% elif param.param_type == "integer" %}, {{ param.name }}=1{% elif param.param_type == "reference" %}{% if "query" in param.variable_name %}, "test_query"{% elif "id" in param.variable_name %}, "test_id"{% elif "participant" in param.variable_name %}, participant_id="test_participant_id"{% else %}, "test_{{ param.name }}"{% endif %}{% else %}, "test_value"{% endif %}{% endfor %}, max_results=10) # Should handle empty responses gracefully pages = list(test_cursor.pages(1)) diff --git a/xdk-gen/templates/python/test_structure.j2 b/xdk-gen/templates/python/test_structure.j2 index c7a8601e..96ec2ea2 100644 --- a/xdk-gen/templates/python/test_structure.j2 +++ b/xdk-gen/templates/python/test_structure.j2 @@ -11,37 +11,37 @@ Generated automatically - do not edit manually. import pytest import inspect from typing import get_type_hints -from xdk.{{ tag|lower }}.client import {{ tag|pascal_case }}Client +from xdk.{{ tag.import_name }}.client import {{ tag.class_name }}Client from xdk import Client -class Test{{ tag|pascal_case }}Structure: - """Test the structure of {{ tag|pascal_case }}Client.""" +class Test{{ tag.class_name }}Structure: + """Test the structure of {{ tag.class_name }}Client.""" def setup_class(self): """Set up test fixtures.""" self.client = Client(base_url="https://api.example.com") - self.{{ tag|lower }}_client = getattr(self.client, "{{ tag|lower }}") + self.{{ tag.property_name }}_client = getattr(self.client, "{{ tag.property_name }}") {% for structural_test in test_spec.structural_tests %} {% for method in structural_test.methods %} - def test_{{ method.method_name|snake_case }}_exists(self): - """Test that {{ method.method_name|snake_case }} method exists with correct signature.""" + def test_{{ method.method_name }}_exists(self): + """Test that {{ method.method_name }} method exists with correct signature.""" # Check method exists - method = getattr({{ tag|pascal_case }}Client, "{{ method.method_name|snake_case }}", None) - assert method is not None, f"Method {{ method.method_name|snake_case }} does not exist on {{ tag|pascal_case }}Client" + method = getattr({{ tag.class_name }}Client, "{{ method.method_name }}", None) + assert method is not None, f"Method {{ method.method_name }} does not exist on {{ tag.class_name }}Client" # Check method is callable - assert callable(method), f"{{ method.method_name|snake_case }} is not callable" + assert callable(method), f"{{ method.method_name }} is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"{{ method.method_name|snake_case }} should have at least 'self' parameter" + assert len(params) >= 1, f"{{ method.method_name }} should have at least 'self' parameter" assert params[0] == 'self', f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') @@ -52,7 +52,7 @@ class Test{{ tag|pascal_case }}Structure: ] for required_param in required_params: - assert required_param in params, f"Required parameter '{required_param}' missing from {{ method.method_name|snake_case }}" + assert required_param in params, f"Required parameter '{required_param}' missing from {{ method.method_name }}" # Check optional parameters have defaults (excluding 'self') optional_params = [ @@ -67,19 +67,19 @@ class Test{{ tag|pascal_case }}Structure: assert param_obj.default is not inspect.Parameter.empty, \ f"Optional parameter '{optional_param}' should have a default value" - def test_{{ method.method_name|snake_case }}_return_annotation(self): - """Test that {{ method.method_name|snake_case }} has proper return type annotation.""" - method = getattr({{ tag|pascal_case }}Client, "{{ method.method_name|snake_case }}") + def test_{{ method.method_name }}_return_annotation(self): + """Test that {{ method.method_name }} has proper return type annotation.""" + method = getattr({{ tag.class_name }}Client, "{{ method.method_name }}") sig = inspect.signature(method) # Check return annotation exists assert sig.return_annotation is not inspect.Signature.empty, \ - f"Method {{ method.method_name|snake_case }} should have return type annotation" + f"Method {{ method.method_name }} should have return type annotation" {% if method.supports_pagination %} - def test_{{ method.method_name|snake_case }}_pagination_params(self): - """Test that {{ method.method_name|snake_case }} has pagination parameters.""" - method = getattr({{ tag|pascal_case }}Client, "{{ method.method_name|snake_case }}") + def test_{{ method.method_name }}_pagination_params(self): + """Test that {{ method.method_name }} has pagination parameters.""" + method = getattr({{ tag.class_name }}Client, "{{ method.method_name }}") sig = inspect.signature(method) params = list(sig.parameters.keys()) @@ -87,7 +87,7 @@ class Test{{ tag|pascal_case }}Structure: pagination_params = ['pagination_token', 'max_results', 'next_token', 'cursor', 'limit'] has_pagination_param = any(param in params for param in pagination_params) assert has_pagination_param, \ - f"Paginated method {{ method.method_name|snake_case }} should have pagination parameters" + f"Paginated method {{ method.method_name }} should have pagination parameters" {% endif %} {% endfor %} @@ -96,14 +96,14 @@ class Test{{ tag|pascal_case }}Structure: """Test that all expected methods exist on the client.""" expected_methods = [ {% for method in structural_test.methods %} - "{{ method.method_name|snake_case }}", + "{{ method.method_name }}", {% endfor %} ] for expected_method in expected_methods: - assert hasattr({{ tag|pascal_case }}Client, expected_method), \ - f"Expected method '{expected_method}' not found on {{ tag|pascal_case }}Client" - assert callable(getattr({{ tag|pascal_case }}Client, expected_method)), \ + assert hasattr({{ tag.class_name }}Client, expected_method), \ + f"Expected method '{expected_method}' not found on {{ tag.class_name }}Client" + assert callable(getattr({{ tag.class_name }}Client, expected_method)), \ f"'{expected_method}' exists but is not callable" {% endfor %} diff --git a/xdk-lib/Cargo.toml b/xdk-lib/Cargo.toml index ada69c71..94515595 100644 --- a/xdk-lib/Cargo.toml +++ b/xdk-lib/Cargo.toml @@ -10,3 +10,7 @@ serde = { workspace = true } serde_json = { workspace = true } thiserror = { workspace = true } colored = { workspace = true } + +[dev-dependencies] +tempfile = "3.8" +pretty_assertions = "1.4" diff --git a/xdk-lib/src/casing.rs b/xdk-lib/src/casing.rs new file mode 100644 index 00000000..b4dd934d --- /dev/null +++ b/xdk-lib/src/casing.rs @@ -0,0 +1,123 @@ +/// Represents different casing conventions for SDK generation +#[derive(Debug, Clone, Copy)] +pub enum Casing { + /// snake_case: my_function_name + Snake, + /// camelCase: myFunctionName + Camel, + /// PascalCase: MyFunctionName + Pascal, + /// kebab-case: my-function-name + Kebab, + /// SCREAMING_SNAKE_CASE: MY_FUNCTION_NAME + ScreamingSnake, +} + +impl Casing { + /// Convert a vector of words to the specified casing convention + pub fn convert_words(&self, words: &[String]) -> String { + match self { + Casing::Snake => words.join("_").to_lowercase(), + Casing::Camel => { + if words.is_empty() { + String::new() + } else { + let mut result = words[0].to_lowercase(); + for word in &words[1..] { + result.push_str(&pascal_case(word)); + } + result + } + } + Casing::Pascal => words + .iter() + .map(|w| pascal_case(w)) + .collect::>() + .join(""), + Casing::Kebab => words.join("-").to_lowercase(), + Casing::ScreamingSnake => words.join("_").to_uppercase(), + } + } + + /// Convert a single string to the specified casing convention + /// This first splits the string into words based on common delimiters and casing + pub fn convert_string(&self, value: &str) -> String { + let words = split_into_words(value); + self.convert_words(&words) + } +} + +/// Split a string into words based on various delimiters and casing conventions +fn split_into_words(value: &str) -> Vec { + let mut words = Vec::new(); + let mut current_word = String::new(); + let chars = value.chars().peekable(); + + for c in chars { + if c == '_' || c == '-' || c == ' ' { + // Delimiter found, finish current word + if !current_word.is_empty() { + words.push(current_word); + current_word = String::new(); + } + } else if c.is_uppercase() { + // Uppercase letter indicates new word boundary (camelCase/PascalCase) + if !current_word.is_empty() { + words.push(current_word); + current_word = String::new(); + } + current_word.push(c.to_lowercase().next().unwrap()); + } else if c.is_alphanumeric() { + current_word.push(c); + } + // Skip other characters + } + + // Add the last word if any + if !current_word.is_empty() { + words.push(current_word); + } + + words +} + +/// Helper for converting a string to PascalCase +pub fn pascal_case(value: &str) -> String { + let mut result = String::new(); + let mut capitalize_next = true; + + for c in value.chars() { + if c == '_' || c == '-' || c == ' ' { + // Skip separators and capitalize the next character + capitalize_next = true; + } else if c.is_uppercase() { + // Uppercase letters indicate word boundaries + result.push(c); + capitalize_next = false; + } else if c.is_alphanumeric() { + if capitalize_next { + result.push(c.to_ascii_uppercase()); + capitalize_next = false; + } else { + result.push(c.to_ascii_lowercase()); + } + } + // Skip non-alphanumeric characters (except separators handled above) + } + + result +} + +/// Helper for converting a string to camelCase +pub fn camel_case(value: &str) -> String { + let pascal = pascal_case(value); + if pascal.is_empty() { + return pascal; + } + + let mut chars = pascal.chars(); + match chars.next() { + None => String::new(), + Some(first) => first.to_lowercase().collect::() + chars.as_str(), + } +} diff --git a/xdk-lib/src/generator.rs b/xdk-lib/src/generator.rs index 565ae9e1..d0b1bba6 100644 --- a/xdk-lib/src/generator.rs +++ b/xdk-lib/src/generator.rs @@ -4,9 +4,8 @@ use std::env; use std::fs; use std::path::{Path, PathBuf}; -use super::models::OperationInfo; -use super::testing::generate_test_specifications; -use super::utils::extract_operations_by_tag; +use super::models::OperationGroup; +use super::openapi::extract_operations_by_tag; use minijinja::Environment; /// Trait that defines the interface for language-specific SDK generators. @@ -87,26 +86,11 @@ pub trait LanguageGenerator { fn generate( &self, env: &Environment, - operations: &HashMap>, + operations: &HashMap, Vec>, output_dir: &Path, ) -> crate::Result<()>; - /// Generates test code for the language (optional) - /// - /// # Parameters - /// * `env` - The MiniJinja environment with templates and filters - /// * `test_spec` - The test specification containing all test scenarios - /// * `output_dir` - The directory where the generated test code will be written - fn generate_tests( - &self, - _env: &Environment, - _test_specs: &HashMap, - _output_dir: &Path, - ) -> crate::Result<()> { - // Default implementation - no test generation - // Languages can override this to implement test generation - Ok(()) - } + // Test generation is now integrated into the main generate method } /// SDK generation function that takes a language generator and an OpenAPI specification @@ -125,20 +109,9 @@ where let operations_by_tag = extract_operations_by_tag(openapi)?; - // Generate test specifications - let test_specs = generate_test_specifications(&operations_by_tag)?; - // Generate SDK code language.generate(&env, &operations_by_tag, output_dir)?; - // Generate tests if test templates are available - language - .generate_tests(&env, &test_specs, output_dir) - .unwrap_or_else(|e| { - // If test generation fails, it's not critical - just log and continue - eprintln!("Warning: Test generation failed: {}", e); - }); - Ok(()) } @@ -151,13 +124,21 @@ where /// # Parameters /// * `name` - Name of the language generator struct to create /// * `filters` - A list of filter functions to be added to the MiniJinja environment +/// * `class_casing` - Casing convention for class/tag names (e.g., Casing::Pascal) +/// * `operation_casing` - Casing convention for operation/method names (e.g., Casing::Snake) +/// * `import_casing` - Casing convention for import/module names (e.g., Casing::Snake for Python, Casing::Pascal for Java) +/// * `variable_casing` - Casing convention for variable/property names (e.g., Casing::Snake) /// * `render` - Configuration for how templates should be rendered /// * `multiple` - Block that defines templates to be rendered for each API tag /// * `render ($template) to ($path)` - Render a template to a specific path +/// * `tests` - Configuration for how test templates should be rendered +/// * `multiple` - Block that defines test templates to be rendered for each API tag +/// * `render ($template) to ($path)` - Render a test template to a specific path /// /// # Example /// ``` /// # use xdk_lib::language; +/// # use xdk_lib::Casing; /// # fn snake_case(value: &str) -> String { /// # value.to_lowercase() /// # } @@ -168,11 +149,22 @@ where /// language! { /// name: Python, /// filters: [snake_case, pascal_case], +/// class_casing: Casing::Pascal, +/// operation_casing: Casing::Snake, +/// import_casing: Casing::Snake, +/// variable_casing: Casing::Snake, /// render: [ /// multiple { // Render once per API tag /// render "module" => "python/src/{}.py" /// }, /// render "__init__" => "python/src/__init__.py" // Render once for the entire SDK +/// ], +/// tests: [ +/// multiple { // Render once per API tag +/// render "test_contracts" => "tests/{}/test_contracts.py", +/// render "test_generic" => "tests/{}/test_generic.py" +/// }, +/// render "conftest" => "tests/conftest.py" // Render once for all tests /// ] /// } /// ``` @@ -181,6 +173,10 @@ macro_rules! language { ( name: $name:ident, filters: [$($filter:ident),*], + class_casing: $class_casing:expr, + operation_casing: $operation_casing:expr, + import_casing: $import_casing:expr, + variable_casing: $variable_casing:expr, render: [ $( multiple { @@ -192,12 +188,25 @@ macro_rules! language { $( render $s_template:expr => $s_path:expr ),* + ], + tests: [ + $( + multiple { + $( + render $test_template:expr => $test_path:expr + ),* + } + ),*, + $( + render $s_test_template:expr => $s_test_path:expr + ),* ] ) => { use std::collections::HashMap; use std::path::{Path, PathBuf}; - use $crate::utils::render_template; - use $crate::models::OperationInfo; + use $crate::templates::render_template; + use $crate::models::TagInfo; + use $crate::models::{OperationInfo, OperationGroup}; use $crate::generator::LanguageGenerator; use $crate::Result; use $crate::models::{OperationContext, TagsContext, TestContext}; @@ -226,21 +235,48 @@ macro_rules! language { fn generate( &self, env: &minijinja::Environment, - operations: &HashMap>, + operations: &HashMap, Vec>, output_dir: &Path, ) -> Result<()> { - let tags: Vec = operations.keys().cloned().collect(); + let tags: Vec> = operations.keys().cloned().collect(); // Handle per-tag template renders $( for tag in &tags { + // Process operations once per tag with proper casing + let operations_with_converted_ids: Vec = operations[tag] + .iter() + .map(|op_group| { + let method_name = $operation_casing.convert_words( + &op_group.metadata.normalized_operation_id, + ); + let class_name = $class_casing.convert_words( + &op_group.metadata.normalized_operation_id, + ); + let processed_parameters = $crate::models::ParameterInfo::from_openapi_parameters( + &op_group.raw_parameters, + $variable_casing, + ); + + let mut operation = op_group + .operation + .clone() + .with_casing(method_name, class_name); + operation.parameters = processed_parameters; + operation + }) + .collect(); + + let tag_info = TagInfo::new(tag, $class_casing, $import_casing, $variable_casing); + let context = OperationContext { + tag: tag_info, + operations: operations_with_converted_ids + }; + $( - let context = OperationContext { - tag: $crate::utils::normalize_tag_to_pascal_case(tag), - operations: operations[tag].clone() - }; - let output_path = PathBuf::from(format!($path, tag.replace(" ", "_").to_lowercase())); + let tag_path = tag.join("_").to_lowercase(); + let output_path = PathBuf::from(format!($path, tag_path)); let content = render_template(env, $template, &context)?; let full_path = output_dir.join(&output_path); std::fs::create_dir_all(full_path.parent().unwrap_or(output_dir))?; @@ -250,133 +286,118 @@ macro_rules! language { )* // Handle singleton template renders (once per SDK) + let tag_infos: Vec<_> = tags.iter().map(|tag| TagInfo::new(tag, $class_casing, $import_casing, $variable_casing)).collect(); + let tags_context = TagsContext { + tags: tag_infos, + }; + $( - let context = TagsContext { - tags: tags.clone(), - }; let output_path = PathBuf::from($s_path); - let content = render_template(env, $s_template, &context)?; + let content = render_template(env, $s_template, &tags_context)?; let full_path = output_dir.join(&output_path); std::fs::create_dir_all(full_path.parent().unwrap_or(output_dir))?; std::fs::write(&full_path, content)?; )* - Ok(()) - } - - /// TODO: Can we make this more generic/a default implementation? - /// Generate test code - can be overridden by specific implementations - fn generate_tests( - &self, - env: &minijinja::Environment, - test_specs: &HashMap, - output_dir: &Path, - ) -> Result<()> { - // Check if language has test templates available - if env.get_template("test_structure").is_ok() || - env.get_template("test_contracts").is_ok() || - env.get_template("test_pagination").is_ok() { - - // Use the same tag iteration as the main generate function - let tags: Vec = test_specs.keys().cloned().collect(); - - for tag in tags { - let context = TestContext { - tag: tag.clone(), - test_spec: test_specs[&tag].clone(), - }; - - let tag_folder = output_dir.join("tests").join(tag.replace(" ", "_").to_lowercase()); - - // Generate structural tests if template exists - if let Ok(template) = env.get_template("test_structure") { - let content = template.render(&context).map_err(|e| $crate::SdkGeneratorError::TemplateError(e))?; - let path = tag_folder.join("test_structure.py"); - std::fs::create_dir_all(tag_folder.clone())?; - std::fs::write(&path, content)?; - } - - // Generate contract tests if template exists - match env.get_template("test_contracts") { - Ok(template) => { - let content = template.render(&context).map_err(|e| $crate::SdkGeneratorError::TemplateError(e))?; - let path = tag_folder.join("test_contracts.py"); - std::fs::create_dir_all(tag_folder.clone())?; - std::fs::write(&path, content)?; - } - Err(e) => { - eprintln!("Debug: test_contracts template not found: {}", e); - } - } - - // Generate pagination tests only if there are valid pagination tests to generate - let has_valid_pagination_tests = !context.test_spec.pagination_tests.is_empty() - && context.test_spec.pagination_tests.iter().any(|test| - !test.method_name.is_empty() && !test.operation_id.is_empty() - ); + // Generate test specifications with proper casing applied + let operations_for_tests: HashMap> = operations + .iter() + .map(|(tag_vec, operation_groups)| { + let tag_string = tag_vec.join("_"); + let operations_with_casing = operation_groups + .iter() + .map(|og| { + let method_name = $operation_casing.convert_words(&og.metadata.normalized_operation_id); + let class_name = $class_casing.convert_words(&og.metadata.normalized_operation_id); + let processed_parameters = $crate::models::ParameterInfo::from_openapi_parameters( + &og.raw_parameters, + $variable_casing, + ); + + let mut operation = og.operation.clone().with_casing(method_name, class_name); + operation.parameters = processed_parameters; + operation + }) + .collect(); + (tag_string, operations_with_casing) + }) + .collect(); + + let test_specs = $crate::testing::generate_test_specifications(&operations_for_tests)?; + + // Convert test specs to use Vec keys to match our tag format + let converted_test_specs: HashMap, $crate::testing::TestSpecification> = test_specs + .iter() + .map(|(tag_string, spec)| { + let tag_vec: Vec = tag_string.split('_').map(|s| s.to_string()).collect(); + (tag_vec, spec.clone()) + }) + .collect(); + + let test_tags: Vec> = converted_test_specs.keys().cloned().collect(); + + // Handle per-tag test template renders + $( + for tag in &test_tags { + let tag_info = TagInfo::new(tag, $class_casing, $import_casing, $variable_casing); + let tag_path = tag.join("_").to_lowercase(); + + if let Some(test_spec) = converted_test_specs.get(tag) { + let test_context = TestContext { + tag: tag_info.clone(), + test_spec: test_spec.clone(), + }; - if has_valid_pagination_tests { - match env.get_template("test_pagination") { - Ok(template) => { - let content = template.render(&context).map_err(|e| $crate::SdkGeneratorError::TemplateError(e))?; - let path = tag_folder.join("test_pagination.py"); - std::fs::create_dir_all(tag_folder.clone())?; - std::fs::write(&path, content)?; - } - Err(e) => { - eprintln!("Debug: test_pagination template not found: {}", e); + $( + if let Ok(_) = env.get_template($test_template) { + // Special handling for pagination tests - only generate if there are valid pagination tests + let should_generate = if $test_template == "test_pagination" { + !test_spec.pagination_tests.is_empty() && + test_spec.pagination_tests.iter().any(|test| + !test.method_name.is_empty() + ) + } else { + true + }; + + if should_generate { + let output_path = PathBuf::from(format!($test_path, tag_path)); + let content = render_template(env, $test_template, &test_context)?; + let full_path = output_dir.join(&output_path); + std::fs::create_dir_all(full_path.parent().unwrap_or(output_dir))?; + std::fs::write(&full_path, content)?; + + // Generate __init__.py for each tag test folder if it's in a subdirectory + if let Some(parent) = full_path.parent() { + if parent != output_dir { + let init_path = parent.join("__init__.py"); + if !init_path.exists() { + std::fs::write(&init_path, "")?; + } + } + } + } } - } + )* } - - // Generate generic tests if template exists - match env.get_template("test_generic") { - Ok(template) => { - let content = template.render(&context).map_err(|e| $crate::SdkGeneratorError::TemplateError(e))?; - let path = tag_folder.join("test_generic.py"); - std::fs::create_dir_all(tag_folder.clone())?; - std::fs::write(&path, content)?; - } - Err(e) => { - eprintln!("Debug: test_generic template not found: {}", e); - } - } - - // Generate __init__.py for each tag folder - let tag_init_path = tag_folder.join("__init__.py"); - std::fs::write(&tag_init_path, "")?; } + )* - // Generate test configuration files for Python - if stringify!($name).to_lowercase() == "python" { - let conftest_content = r#""""Test configuration and fixtures.""" - -import pytest -from unittest.mock import Mock -from xdk import Client - - -@pytest.fixture -def mock_client(): - """Provide a mock client for testing.""" - return Client(base_url="https://api.example.com") - - -@pytest.fixture -def mock_session(): - """Provide a mock session for HTTP requests.""" - return Mock() -"#; - - let conftest_path = output_dir.join("tests").join("conftest.py"); - std::fs::create_dir_all(conftest_path.parent().unwrap_or(output_dir))?; - std::fs::write(&conftest_path, conftest_content)?; + // Handle singleton test template renders (once per SDK) + let test_tag_infos: Vec<_> = test_tags.iter().map(|tag| TagInfo::new(tag, $class_casing, $import_casing, $variable_casing)).collect(); + let test_tags_context = TagsContext { + tags: test_tag_infos, + }; - // Generate __init__.py for tests package - let tests_init_path = output_dir.join("tests").join("__init__.py"); - std::fs::write(&tests_init_path, "")?; + $( + if let Ok(_) = env.get_template($s_test_template) { + let output_path = PathBuf::from($s_test_path); + let content = render_template(env, $s_test_template, &test_tags_context)?; + let full_path = output_dir.join(&output_path); + std::fs::create_dir_all(full_path.parent().unwrap_or(output_dir))?; + std::fs::write(&full_path, content)?; } - } + )* Ok(()) } diff --git a/xdk-lib/src/lib.rs b/xdk-lib/src/lib.rs index e032fda1..27b639d2 100644 --- a/xdk-lib/src/lib.rs +++ b/xdk-lib/src/lib.rs @@ -12,18 +12,25 @@ /// - `error`: Error types and handling for SDK generation /// - `generator`: The SDK generator interface and implementation /// - `models`: Common data models for SDK generation -/// - `utils`: Utility functions for SDK generation /// - `testing`: Test generation for SDK generation +/// - `casing`: Casing conversion utilities for different naming conventions +pub mod casing; pub mod error; pub mod generator; pub mod logging; pub mod models; +pub mod openapi; +pub mod templates; pub mod testing; -pub mod utils; +pub use casing::*; pub use error::*; pub use generator::*; pub use logging::*; +// Re-export important functions for better API +pub use openapi::extract_operations_by_tag; +pub use templates::render_template; + /// Result type for SDK generator operations pub type Result = std::result::Result; diff --git a/xdk-lib/src/models.rs b/xdk-lib/src/models.rs index 2216a33c..b1127b11 100644 --- a/xdk-lib/src/models.rs +++ b/xdk-lib/src/models.rs @@ -1,18 +1,33 @@ -use crate::testing::TestSpecification; +use crate::Casing; /// Common data models for SDK generation /// /// This file contains the core data models that are used across different language generators. +/// It also provides factory functions for creating properly configured model instances. /// /// For now we are sharing context structs between languages. /// If we require language specific contexts in the future, we will revist the design. -use openapi::{Parameter, RefOrValue, RequestBody, Response, SecurityRequirement, StatusCode}; +use crate::testing::TestSpecification; +use openapi::{ + Parameter, RefOrValue, RequestBody, Response, Schema, SecurityRequirement, StatusCode, +}; use serde::Serialize; use std::collections::HashMap; + +#[derive(Debug, Serialize, Clone)] +pub struct OperationGroup { + pub operation: OperationInfo, + pub metadata: Metadata, + /// Raw parameters from OpenAPI (before casing is applied) + pub raw_parameters: Option>>, +} + /// Information about an operation in the OpenAPI spec #[derive(Debug, Serialize, Clone)] pub struct OperationInfo { - /// Operation ID from the OpenAPI spec - pub operation_id: String, + /// Class name for Request/Response models (e.g., "GetUsers") + pub class_name: String, + /// Method name (same as operation_id for consistency) + pub method_name: String, /// HTTP method (GET, POST, etc.) pub method: String, /// Path for the operation @@ -23,30 +38,153 @@ pub struct OperationInfo { pub summary: Option, /// Security requirements for the operation pub security: Option>, - /// Parameters for the operation - pub parameters: Option>>, + /// Parameters for the operation (processed with casing applied) + pub parameters: Option>, /// Request body information pub request_body: Option, /// Response information pub responses: HashMap, } +#[derive(Debug, Serialize, Clone)] +pub struct Metadata { + pub normalized_operation_id: Vec, +} + /// Context for rendering a client class template #[derive(Debug, Serialize)] pub struct OperationContext { - pub tag: String, + pub tag: TagInfo, pub operations: Vec, } +/// Information about a tag with different casing variants +#[derive(Debug, Serialize, Clone)] +pub struct TagInfo { + /// Original tag words + pub original: Vec, + /// Class name (e.g., "CommunityNotes") + pub class_name: String, + /// Import name/module name (e.g., "community_notes") + pub import_name: String, + /// Property name (e.g., "community_notes") + pub property_name: String, + /// Display name (e.g., "Community Notes") + pub display_name: String, +} + +/// Information about a parameter with different casing variants +#[derive(Debug, Serialize, Clone)] +pub struct ParameterInfo { + /// Original parameter name from OpenAPI + pub original_name: String, + /// Variable name (cased for target language, e.g., "user_id") + pub variable_name: String, + /// Parameter location (path, query, header, cookie) + pub location: String, + /// Whether the parameter is required + pub required: bool, + /// Parameter type + pub param_type: String, + /// Parameter description + pub description: Option, + /// Parameter schema (for complex validation) + pub schema: Option>, +} + /// Context for rendering the main client template that imports all tag-specific clients #[derive(Debug, Serialize)] pub struct TagsContext { - pub tags: Vec, + pub tags: Vec, } /// Context for rendering test templates #[derive(Debug, Serialize)] pub struct TestContext { - pub tag: String, + pub tag: TagInfo, pub test_spec: TestSpecification, } + +impl OperationInfo { + pub fn with_casing(self, method_name: String, class_name: String) -> Self { + Self { + method_name, + class_name, + ..self + } + } +} + +impl TagInfo { + /// Create TagInfo with different casing variants based on language configuration + pub fn new( + tag_words: &[String], + class_casing: Casing, + import_casing: Casing, + property_casing: Casing, + ) -> Self { + Self { + original: tag_words.to_vec(), + class_name: class_casing.convert_words(tag_words), + import_name: import_casing.convert_words(tag_words), + property_name: property_casing.convert_words(tag_words), + display_name: tag_words.join(" "), + } + } +} + +impl ParameterInfo { + /// Convert OpenAPI parameters to ParameterInfo with casing applied + pub fn from_openapi_parameters( + parameters: &Option>>, + variable_casing: Casing, + ) -> Option> { + parameters.as_ref().map(|params| { + params + .iter() + .filter_map(|param_ref| { + // Handle both direct parameters and parameter references + let param = match param_ref { + RefOrValue::Value(p) => p, + RefOrValue::Reference { .. } => return None, // Skip references for now + }; + + if let (Some(name), Some(location)) = (¶m.name, ¶m.r#in) { + let param_type = extract_param_type(param); + let is_required = param.required.unwrap_or(false) || location == "path"; + + Some(Self { + original_name: name.clone(), + variable_name: variable_casing.convert_string(name), + location: location.clone(), + required: is_required, + param_type, + description: param.description.clone(), + schema: param.schema.clone(), + }) + } else { + None + } + }) + .collect() + }) + } +} + +/// Extract parameter type from parameter schema +fn extract_param_type(param: &Parameter) -> String { + if let Some(RefOrValue::Value(Schema::Typed(typed))) = ¶m.schema { + match typed.as_ref() { + openapi::TypedSchema::String(_) => "string".to_string(), + openapi::TypedSchema::Integer(_) => "integer".to_string(), + openapi::TypedSchema::Number(_) => "number".to_string(), + openapi::TypedSchema::Boolean(_) => "boolean".to_string(), + openapi::TypedSchema::Array(_) => "array".to_string(), + openapi::TypedSchema::Object(_) => "object".to_string(), + } + } else if let Some(RefOrValue::Reference { .. }) = ¶m.schema { + "reference".to_string() + } else { + "any".to_string() + } +} diff --git a/xdk-lib/src/openapi.rs b/xdk-lib/src/openapi.rs new file mode 100644 index 00000000..59510a2a --- /dev/null +++ b/xdk-lib/src/openapi.rs @@ -0,0 +1,126 @@ +//! OpenAPI specification parsing and processing +//! +//! This module handles the core logic for parsing OpenAPI specifications +//! and transforming them into the internal data structures used by the +//! XDK generator system. + +use crate::Result; +use crate::models::{Metadata, OperationGroup, OperationInfo}; +use openapi::OpenApi; +use std::collections::HashMap; + +/// Extract operations by tag from the OpenAPI specification with automatic name transformations +pub fn extract_operations_by_tag( + openapi: &OpenApi, +) -> Result, Vec>> { + let mut operations_by_tag: HashMap, Vec> = HashMap::new(); + + /// Helper function to process an operation and add it to the operations_by_tag map + fn process_operation( + operations_by_tag: &mut HashMap, Vec>, + path: &str, + method: &str, + operation: &Option, + ) { + if let Some(op) = operation { + if let Some(tags) = &op.tags { + if let Some(first_tag) = tags.first() { + let normalized_tag: Vec = normalize_tag(first_tag); + + let normalized_operation_id: Vec = + normalize_operation_id(&op.operation_id); + + let operation_info = OperationInfo { + path: path.to_string(), + method: method.to_string(), + class_name: String::new(), // Will be set when casing is applied + method_name: String::new(), // Will be set when casing is applied + summary: op.summary.clone(), + description: op.description.clone(), + parameters: None, // Will be processed with casing in the macro + security: op.security.clone(), + request_body: op.request_body.clone(), + responses: op.responses.clone(), + }; + let operation_group = OperationGroup { + operation: operation_info, + metadata: Metadata { + normalized_operation_id: clean_operation_id( + normalized_operation_id, + normalized_tag.clone(), + ), + }, + raw_parameters: op.parameters.clone(), + }; + operations_by_tag + .entry(normalized_tag) + .or_default() + .push(operation_group); + } + } + } + } + + for (path, path_item) in &openapi.paths { + // Process each HTTP method type using the same logic + process_operation(&mut operations_by_tag, path, "get", &path_item.get); + process_operation(&mut operations_by_tag, path, "post", &path_item.post); + process_operation(&mut operations_by_tag, path, "put", &path_item.put); + process_operation(&mut operations_by_tag, path, "delete", &path_item.delete); + process_operation(&mut operations_by_tag, path, "patch", &path_item.patch); + } + + Ok(operations_by_tag) +} + +/// Normalize tag names for consistent processing +pub fn normalize_tag(tag: &str) -> Vec { + tag.split_whitespace() + .map(|word| { + word.to_lowercase() + .replace("tweets", "posts") + .replace("tweet", "post") + }) + .collect() +} + +/// Normalize operation ID into word components +pub fn normalize_operation_id(operation_id: &str) -> Vec { + let chars: Vec = operation_id.chars().collect(); + let mut words: Vec = Vec::new(); + let mut current = String::new(); + + for i in 0..chars.len() { + let ch = chars[i]; + if ch.is_uppercase() { + let prev_lower = i > 0 && chars[i - 1].is_lowercase(); + let prev_upper = i > 0 && chars[i - 1].is_uppercase(); + let next_lower = i + 1 < chars.len() && chars[i + 1].is_lowercase(); + if !current.is_empty() && (prev_lower || (prev_upper && next_lower)) { + words.push(current.clone()); + current.clear(); + } + } + current.push(ch.to_lowercase().next().unwrap()); + } + + if !current.is_empty() { + words.push(current); + } + + words +} + +/// Clean operation ID by removing words that appear in the tag +pub fn clean_operation_id( + operation_id_as_vec: Vec, + tag_as_vec: Vec, +) -> Vec { + let mut cleaned_operation_id = Vec::new(); + for word in operation_id_as_vec { + if !tag_as_vec.contains(&word) { + cleaned_operation_id.push(word.to_lowercase()); + } + } + cleaned_operation_id +} diff --git a/xdk-lib/src/templates.rs b/xdk-lib/src/templates.rs new file mode 100644 index 00000000..4fbe86a0 --- /dev/null +++ b/xdk-lib/src/templates.rs @@ -0,0 +1,25 @@ +//! Template rendering utilities +//! +//! This module provides functionality for rendering Jinja2 templates +//! with context data for SDK generation. + +use crate::Result; +use minijinja::Environment; +use serde::Serialize; + +/// Render a template with the given context +/// +/// # Arguments +/// * `env` - The MiniJinja environment containing templates +/// * `template` - The name of the template to render +/// * `context` - The context data to pass to the template +/// +/// # Returns +/// The rendered template content as a string +pub fn render_template( + env: &Environment, + template: &str, + context: &C, +) -> Result { + Ok(env.get_template(template)?.render(context)?) +} diff --git a/xdk-lib/src/testing.rs b/xdk-lib/src/testing.rs index e1372f9a..fb5c6588 100644 --- a/xdk-lib/src/testing.rs +++ b/xdk-lib/src/testing.rs @@ -123,7 +123,7 @@ //! This system enables the XDK generator to produce comprehensive, realistic test suites for any //! target language while maintaining consistency and leveraging the full OpenAPI specification. use crate::models::OperationInfo; -use openapi::{Parameter, RefOrValue, RequestBody, Schema, TypedSchema}; +use openapi::{RefOrValue, RequestBody, Schema, TypedSchema}; use serde::Serialize; use std::collections::HashMap; @@ -154,10 +154,10 @@ pub struct StructuralTest { /// Method signature information for structural testing #[derive(Debug, Serialize, Clone)] pub struct MethodSignature { - /// Method name (e.g., "get_users") + /// Method name (e.g., "get_users") - cased for the target language pub method_name: String, - /// Original operation ID from OpenAPI - pub operation_id: String, + /// Class name (e.g., "GetUsers") - for Request/Response models + pub class_name: String, /// Required parameters pub required_params: Vec, /// Optional parameters @@ -171,8 +171,10 @@ pub struct MethodSignature { /// Parameter information for testing #[derive(Debug, Serialize, Clone)] pub struct TestParameter { - /// Parameter name + /// Parameter name (original from OpenAPI) pub name: String, + /// Variable name (cased for the target language) + pub variable_name: String, /// Parameter type (language-neutral) pub param_type: String, /// Where the parameter goes (query, path, header, body) @@ -186,8 +188,10 @@ pub struct TestParameter { /// Contract test specification #[derive(Debug, Serialize, Clone)] pub struct ContractTest { - /// Operation ID being tested - pub operation_id: String, + /// Method name (cased for target language, e.g., "get_users") + pub method_name: String, + /// Class name (cased for models, e.g., "GetUsers") + pub class_name: String, /// HTTP method pub method: String, /// URL path template @@ -231,8 +235,6 @@ pub struct ResponseField { /// Pagination test specification #[derive(Debug, Serialize, Clone)] pub struct PaginationTest { - /// Operation ID that supports pagination - pub operation_id: String, /// Method name for testing pub method_name: String, /// Required parameters for this operation (excluding pagination params) @@ -250,8 +252,8 @@ pub struct PaginationTest { /// Mock scenario for integration testing #[derive(Debug, Serialize, Clone)] pub struct MockScenario { - /// Operation ID this scenario tests - pub operation_id: String, + /// Method name this scenario tests + pub method_name: String, /// Scenario name (e.g., "success", "not_found", "rate_limit") pub scenario_name: String, /// HTTP status code to mock @@ -330,50 +332,37 @@ fn generate_method_signature(operation: &OperationInfo) -> MethodSignature { let (required_params, optional_params) = extract_parameters(operation); MethodSignature { - method_name: operation.operation_id.clone(), - operation_id: operation.operation_id.clone(), + method_name: operation.method_name.clone(), + class_name: operation.class_name.clone(), required_params, optional_params, - return_type: format!("{}Response", operation.operation_id), + return_type: format!("{}Response", operation.class_name), supports_pagination: detect_pagination_support(operation), } } -/// Extract parameters from operation +/// Extract parameters from operation (convert ParameterInfo to TestParameter) fn extract_parameters(operation: &OperationInfo) -> (Vec, Vec) { let mut required_params = Vec::new(); let mut optional_params = Vec::new(); if let Some(parameters) = &operation.parameters { - for param_ref in parameters { - // Handle both direct parameters and parameter references - let param = match param_ref { - RefOrValue::Value(p) => p, - RefOrValue::Reference { - path: _, - resolved: _, - } => continue, // References are only used for components (requests/responses), not parameters - }; - - if let (Some(name), Some(location)) = (¶m.name, ¶m.r#in) { - // Only include path and query parameters for testing - if location == "path" || location == "query" { - let param_type = extract_param_type(param); - let is_required = param.required.unwrap_or(false) || location == "path"; // Path params are always required - - let test_param = TestParameter { - name: name.clone(), - param_type, - location: location.clone(), - required: is_required, - description: param.description.clone(), - }; - - if is_required { - required_params.push(test_param); - } else { - optional_params.push(test_param); - } + for param in parameters { + // Only include path and query parameters for testing + if param.location == "path" || param.location == "query" { + let test_param = TestParameter { + name: param.original_name.clone(), + variable_name: param.variable_name.clone(), // Already cased + param_type: param.param_type.clone(), + location: param.location.clone(), + required: param.required, + description: param.description.clone(), + }; + + if param.required { + required_params.push(test_param); + } else { + optional_params.push(test_param); } } } @@ -382,30 +371,13 @@ fn extract_parameters(operation: &OperationInfo) -> (Vec, Vec String { - if let Some(RefOrValue::Value(Schema::Typed(typed))) = ¶m.schema { - match typed.as_ref() { - TypedSchema::String(_) => "string".to_string(), - TypedSchema::Integer(_) => "integer".to_string(), - TypedSchema::Number(_) => "number".to_string(), - TypedSchema::Boolean(_) => "boolean".to_string(), - TypedSchema::Array(_) => "array".to_string(), - TypedSchema::Object(_) => "object".to_string(), - } - } else if let Some(RefOrValue::Reference { .. }) = ¶m.schema { - "reference".to_string() - } else { - "any".to_string() - } -} - /// Generate contract test from operation fn generate_contract_test(operation: &OperationInfo) -> ContractTest { let (required_params, optional_params) = extract_parameters(operation); ContractTest { - operation_id: operation.operation_id.clone(), + method_name: operation.method_name.clone(), + class_name: operation.class_name.clone(), method: operation.method.clone(), path: operation.path.clone(), required_params, @@ -538,27 +510,17 @@ fn extract_security_requirements(operation: &OperationInfo) -> Vec { fn detect_pagination_support(operation: &OperationInfo) -> bool { if let Some(parameters) = &operation.parameters { let has_token = parameters.iter().any(|param| { - if let RefOrValue::Value(param) = param { - if let Some(name) = ¶m.name { - matches!(name.as_str(), "pagination_token" | "next_token" | "cursor") - } else { - false - } - } else { - false - } + matches!( + param.original_name.as_str(), + "pagination_token" | "next_token" | "cursor" + ) }); let has_limit = parameters.iter().any(|param| { - if let RefOrValue::Value(param) = param { - if let Some(name) = ¶m.name { - matches!(name.as_str(), "max_results" | "limit" | "count") - } else { - false - } - } else { - false - } + matches!( + param.original_name.as_str(), + "max_results" | "limit" | "count" + ) }); // Require BOTH token and limit parameters for true pagination support @@ -585,8 +547,7 @@ fn generate_pagination_test(operation: &OperationInfo) -> PaginationTest { .collect(); PaginationTest { - operation_id: operation.operation_id.clone(), - method_name: operation.operation_id.clone(), + method_name: operation.method_name.clone(), required_params: filtered_required_params, token_param, max_results_param, @@ -602,18 +563,14 @@ fn extract_pagination_params(operation: &OperationInfo) -> (Option, Opti if let Some(parameters) = &operation.parameters { for param in parameters { - if let RefOrValue::Value(param) = param { - if let Some(name) = ¶m.name { - match name.as_str() { - "pagination_token" | "next_token" | "cursor" => { - token_param = Some(name.clone()); - } - "max_results" | "limit" | "count" => { - max_results_param = Some(name.clone()); - } - _ => {} - } + match param.original_name.as_str() { + "pagination_token" | "next_token" | "cursor" => { + token_param = Some(param.original_name.clone()); } + "max_results" | "limit" | "count" => { + max_results_param = Some(param.original_name.clone()); + } + _ => {} } } } @@ -627,7 +584,7 @@ fn generate_mock_scenarios(operation: &OperationInfo) -> Vec { // Success scenario scenarios.push(MockScenario { - operation_id: operation.operation_id.clone(), + method_name: operation.method_name.clone(), scenario_name: "success".to_string(), status_code: 200, response_body: generate_success_response(operation), @@ -637,7 +594,7 @@ fn generate_mock_scenarios(operation: &OperationInfo) -> Vec { // Error scenarios scenarios.push(MockScenario { - operation_id: operation.operation_id.clone(), + method_name: operation.method_name.clone(), scenario_name: "not_found".to_string(), status_code: 404, response_body: serde_json::json!({ @@ -651,7 +608,7 @@ fn generate_mock_scenarios(operation: &OperationInfo) -> Vec { }); scenarios.push(MockScenario { - operation_id: operation.operation_id.clone(), + method_name: operation.method_name.clone(), scenario_name: "rate_limit".to_string(), status_code: 429, response_body: serde_json::json!({ @@ -701,22 +658,18 @@ fn generate_request_params(operation: &OperationInfo) -> HashMap String { - // Normalize tag to lowercase for case-insensitive comparison - let normalized_tag = tag.to_lowercase(); - - // Handle special cases for better naming - match normalized_tag.as_str() { - "tweets" => "posts".to_string(), - _ => normalized_tag.to_lowercase(), - } -} - -/// Convert normalized tag to PascalCase for class names -pub fn normalize_tag_to_pascal_case(tag: &str) -> String { - let normalized = normalize_tag(tag); - - // Convert snake_case to PascalCase - normalized - .split('_') - .map(|word| { - let mut chars = word.chars(); - match chars.next() { - None => String::new(), - Some(first) => first.to_uppercase().collect::() + chars.as_str(), - } - }) - .collect::() -} - -pub fn normalize_operation_id(operation_id: &str, _path: &str, _method: &str, tag: &str) -> String { - let mut words = split_into_words(operation_id); - - // Generate singular/plural variations of the tag - let tag_variations = generate_tag_variations(tag); - - // Remove the first occurrence of any tag variation - for variation in tag_variations { - if let Some(start_index) = find_tag_sequence(&words, &variation) { - remove_tag_sequence(&mut words, start_index, &variation); - break; // Only remove the first occurrence - } - } - - // Convert words back to camelCase - words_to_camel_case(&words) -} - -/// Convert a vector of words to camelCase -fn words_to_camel_case(words: &[String]) -> String { - if words.is_empty() { - return String::new(); - } - - let mut result = String::new(); - - for (i, word) in words.iter().enumerate() { - if i == 0 { - // First word should be lowercase - result.push_str(&word.to_lowercase()); - } else { - // Subsequent words should be capitalized - let mut chars = word.chars(); - if let Some(first) = chars.next() { - result.push(first.to_uppercase().next().unwrap()); - result.push_str(&chars.as_str().to_lowercase()); - } - } - } - - result -} - -/// Generate singular and plural variations of a tag for matching -fn generate_tag_variations(tag: &str) -> Vec { - let mut variations = vec![tag.to_string()]; - - // Add singular version if tag is plural - if tag.ends_with('s') { - variations.push(tag[..tag.len() - 1].to_string()); - } else { - // Add plural version if tag is singular - variations.push(format!("{}s", tag)); - } - - variations -} - -/// Find the starting index of a tag sequence in the words vector -fn find_tag_sequence(words: &[String], tag: &str) -> Option { - // Split by both underscore and space - let tag_words: Vec<&str> = tag.split(&['_', ' '][..]).collect(); - - for (i, window) in words.windows(tag_words.len()).enumerate() { - let window_lower: Vec = window.iter().map(|w| w.to_lowercase()).collect(); - let tag_words_string: Vec = tag_words.iter().map(|&w| w.to_string()).collect(); - if window_lower == tag_words_string { - return Some(i); - } - } - - None -} - -/// Remove a tag sequence from the words vector starting at the given index -fn remove_tag_sequence(words: &mut Vec, start_index: usize, tag: &str) { - // Split by both underscore and space - let tag_words: Vec<&str> = tag.split(&['_', ' '][..]).collect(); - - // Remove the sequence of words - for _ in 0..tag_words.len() { - if start_index < words.len() { - words.remove(start_index); - } - } -} - -/// Split a camelCase string into words based on uppercase boundaries -fn split_into_words(s: &str) -> Vec { - if s.is_empty() { - return vec![]; - } - - let mut words = Vec::new(); - let mut current_word = String::new(); - let chars: Vec = s.chars().collect(); - - for (i, &ch) in chars.iter().enumerate() { - if ch.is_uppercase() && i > 0 { - // If we have a current word and encounter an uppercase letter, start a new word - if !current_word.is_empty() { - words.push(current_word.clone()); - current_word.clear(); - } - current_word.push(ch.to_lowercase().next().unwrap()); - } else { - current_word.push(ch); - } - } - - // Add the last word if it's not empty - if !current_word.is_empty() { - words.push(current_word); - } - - // Filter out empty strings - words.into_iter().filter(|word| !word.is_empty()).collect() -} - -/// Extract operations by tag from the OpenAPI specification with automatic name transformations -pub fn extract_operations_by_tag(openapi: &OpenApi) -> Result>> { - let mut operations_by_tag: HashMap> = HashMap::new(); - - /// Helper function to process an operation and add it to the operations_by_tag map - fn process_operation( - operations_by_tag: &mut HashMap>, - path: &str, - method: &str, - operation: &Option, - ) { - if let Some(op) = operation { - if let Some(tags) = &op.tags { - // Only use the first tag - if let Some(first_tag) = tags.first() { - // Normalize tag name - let normalized_tag = normalize_tag(first_tag); - - // Normalize operation ID - let normalized_operation_id = - normalize_operation_id(&op.operation_id, path, method, &normalized_tag); - - let operation_info = OperationInfo { - path: path.to_string(), - method: method.to_string(), - operation_id: normalized_operation_id, - summary: op.summary.clone(), - description: op.description.clone(), - parameters: op.parameters.clone(), - security: op.security.clone(), - request_body: op.request_body.clone(), - responses: op.responses.clone(), - }; - operations_by_tag - .entry(normalized_tag) - .or_default() - .push(operation_info); - } - } - } - } - - for (path, path_item) in &openapi.paths { - // Process each HTTP method type using the same logic - process_operation(&mut operations_by_tag, path, "get", &path_item.get); - process_operation(&mut operations_by_tag, path, "post", &path_item.post); - process_operation(&mut operations_by_tag, path, "put", &path_item.put); - process_operation(&mut operations_by_tag, path, "delete", &path_item.delete); - process_operation(&mut operations_by_tag, path, "patch", &path_item.patch); - } - - Ok(operations_by_tag) -} - -pub fn render_template( - env: &Environment, - template: &str, - context: &C, -) -> Result { - Ok(env.get_template(template)?.render(context)?) -} diff --git a/xdk-lib/tests/casing_tests.rs b/xdk-lib/tests/casing_tests.rs new file mode 100644 index 00000000..cd173c1c --- /dev/null +++ b/xdk-lib/tests/casing_tests.rs @@ -0,0 +1,211 @@ +use xdk_lib::Casing; + +#[test] +fn test_casing_enum_convert_words() { + let words = vec!["hello".to_string(), "world".to_string()]; + + assert_eq!(Casing::Snake.convert_words(&words), "hello_world"); + assert_eq!(Casing::Pascal.convert_words(&words), "HelloWorld"); + assert_eq!(Casing::Camel.convert_words(&words), "helloWorld"); + assert_eq!(Casing::Kebab.convert_words(&words), "hello-world"); + assert_eq!(Casing::ScreamingSnake.convert_words(&words), "HELLO_WORLD"); +} + +#[test] +fn test_casing_enum_single_word() { + let words = vec!["user".to_string()]; + + assert_eq!(Casing::Snake.convert_words(&words), "user"); + assert_eq!(Casing::Pascal.convert_words(&words), "User"); + assert_eq!(Casing::Camel.convert_words(&words), "user"); + assert_eq!(Casing::Kebab.convert_words(&words), "user"); + assert_eq!(Casing::ScreamingSnake.convert_words(&words), "USER"); +} + +#[test] +fn test_casing_enum_empty_words() { + let words: Vec = vec![]; + + assert_eq!(Casing::Snake.convert_words(&words), ""); + assert_eq!(Casing::Pascal.convert_words(&words), ""); + assert_eq!(Casing::Camel.convert_words(&words), ""); + assert_eq!(Casing::Kebab.convert_words(&words), ""); + assert_eq!(Casing::ScreamingSnake.convert_words(&words), ""); +} + +#[test] +fn test_casing_enum_complex_words() { + let words = vec![ + "get".to_string(), + "user".to_string(), + "profile".to_string(), + "data".to_string(), + ]; + + assert_eq!(Casing::Snake.convert_words(&words), "get_user_profile_data"); + assert_eq!(Casing::Pascal.convert_words(&words), "GetUserProfileData"); + assert_eq!(Casing::Camel.convert_words(&words), "getUserProfileData"); + assert_eq!(Casing::Kebab.convert_words(&words), "get-user-profile-data"); + assert_eq!( + Casing::ScreamingSnake.convert_words(&words), + "GET_USER_PROFILE_DATA" + ); +} + +#[test] +fn test_casing_enum_mixed_case_words() { + // Test with already cased words + let words = vec!["getUserID".to_string()]; + + assert_eq!(Casing::Snake.convert_words(&words), "getuserid"); + assert_eq!(Casing::Pascal.convert_words(&words), "GetUserID"); + assert_eq!(Casing::Camel.convert_words(&words), "getuserid"); + assert_eq!(Casing::Kebab.convert_words(&words), "getuserid"); + assert_eq!(Casing::ScreamingSnake.convert_words(&words), "GETUSERID"); +} + +#[test] +fn test_casing_enum_special_characters() { + // Test with words containing special characters + let words = vec!["hello_world".to_string()]; + + assert_eq!(Casing::Snake.convert_words(&words), "hello_world"); + assert_eq!(Casing::Pascal.convert_words(&words), "HelloWorld"); + assert_eq!(Casing::Camel.convert_words(&words), "hello_world"); + assert_eq!(Casing::Kebab.convert_words(&words), "hello_world"); + assert_eq!(Casing::ScreamingSnake.convert_words(&words), "HELLO_WORLD"); +} + +#[test] +fn test_casing_enum_numbers() { + let words = vec!["user".to_string(), "v2".to_string(), "api".to_string()]; + + assert_eq!(Casing::Snake.convert_words(&words), "user_v2_api"); + assert_eq!(Casing::Pascal.convert_words(&words), "UserV2Api"); + assert_eq!(Casing::Camel.convert_words(&words), "userV2Api"); + assert_eq!(Casing::Kebab.convert_words(&words), "user-v2-api"); + assert_eq!(Casing::ScreamingSnake.convert_words(&words), "USER_V2_API"); +} + +#[test] +fn test_casing_enum_real_world_examples() { + // Test with real operation names that would be used in practice + let get_user_profile = vec!["get".to_string(), "user".to_string(), "profile".to_string()]; + + assert_eq!( + Casing::Snake.convert_words(&get_user_profile), + "get_user_profile" + ); + assert_eq!( + Casing::Pascal.convert_words(&get_user_profile), + "GetUserProfile" + ); + assert_eq!( + Casing::Camel.convert_words(&get_user_profile), + "getUserProfile" + ); + assert_eq!( + Casing::Kebab.convert_words(&get_user_profile), + "get-user-profile" + ); + assert_eq!( + Casing::ScreamingSnake.convert_words(&get_user_profile), + "GET_USER_PROFILE" + ); + + // Test tag names + let community_notes = vec!["community".to_string(), "notes".to_string()]; + + assert_eq!( + Casing::Snake.convert_words(&community_notes), + "community_notes" + ); + assert_eq!( + Casing::Pascal.convert_words(&community_notes), + "CommunityNotes" + ); + assert_eq!( + Casing::Camel.convert_words(&community_notes), + "communityNotes" + ); + assert_eq!( + Casing::Kebab.convert_words(&community_notes), + "community-notes" + ); + assert_eq!( + Casing::ScreamingSnake.convert_words(&community_notes), + "COMMUNITY_NOTES" + ); +} + +#[test] +fn test_casing_enum_copy_clone() { + let casing = Casing::Pascal; + let casing_copy = casing; + let casing_clone = casing; + + let words = vec!["test".to_string()]; + + assert_eq!(casing.convert_words(&words), "Test"); + assert_eq!(casing_copy.convert_words(&words), "Test"); + assert_eq!(casing_clone.convert_words(&words), "Test"); +} + +#[test] +fn test_casing_enum_convert_string() { + // Test converting camelCase strings + assert_eq!(Casing::Snake.convert_string("maxResults"), "max_results"); + assert_eq!(Casing::Pascal.convert_string("maxResults"), "MaxResults"); + assert_eq!(Casing::Camel.convert_string("maxResults"), "maxResults"); + assert_eq!(Casing::Kebab.convert_string("maxResults"), "max-results"); + assert_eq!( + Casing::ScreamingSnake.convert_string("maxResults"), + "MAX_RESULTS" + ); + + // Test converting PascalCase strings + assert_eq!( + Casing::Snake.convert_string("GetUserProfile"), + "get_user_profile" + ); + assert_eq!( + Casing::Pascal.convert_string("GetUserProfile"), + "GetUserProfile" + ); + assert_eq!( + Casing::Camel.convert_string("GetUserProfile"), + "getUserProfile" + ); + assert_eq!( + Casing::Kebab.convert_string("GetUserProfile"), + "get-user-profile" + ); + assert_eq!( + Casing::ScreamingSnake.convert_string("GetUserProfile"), + "GET_USER_PROFILE" + ); + + // Test converting snake_case strings + assert_eq!(Casing::Snake.convert_string("user_id"), "user_id"); + assert_eq!(Casing::Pascal.convert_string("user_id"), "UserId"); + assert_eq!(Casing::Camel.convert_string("user_id"), "userId"); + assert_eq!(Casing::Kebab.convert_string("user_id"), "user-id"); + assert_eq!(Casing::ScreamingSnake.convert_string("user_id"), "USER_ID"); + + // Test converting kebab-case strings + assert_eq!(Casing::Snake.convert_string("user-profile"), "user_profile"); + assert_eq!(Casing::Pascal.convert_string("user-profile"), "UserProfile"); + assert_eq!(Casing::Camel.convert_string("user-profile"), "userProfile"); + assert_eq!(Casing::Kebab.convert_string("user-profile"), "user-profile"); + assert_eq!( + Casing::ScreamingSnake.convert_string("user-profile"), + "USER_PROFILE" + ); +} + +#[test] +fn test_casing_enum_debug() { + let casing = Casing::Pascal; + let debug_string = format!("{:?}", casing); + assert_eq!(debug_string, "Pascal"); +} diff --git a/xdk-lib/tests/error_tests.rs b/xdk-lib/tests/error_tests.rs new file mode 100644 index 00000000..07c08543 --- /dev/null +++ b/xdk-lib/tests/error_tests.rs @@ -0,0 +1,144 @@ +use std::io; +use xdk_lib::{Result, SdkGeneratorError}; + +#[test] +fn test_io_error_conversion() { + let io_error = io::Error::new(io::ErrorKind::NotFound, "File not found"); + let xdk_error: SdkGeneratorError = io_error.into(); + + match xdk_error { + SdkGeneratorError::IoError(err) => { + assert_eq!(err.kind(), io::ErrorKind::NotFound); + assert_eq!(err.to_string(), "File not found"); + } + _ => panic!("Expected IoError"), + } +} + +#[test] +fn test_template_error_conversion() { + let template_error = minijinja::Error::new( + minijinja::ErrorKind::TemplateNotFound, + "Template 'missing' not found", + ); + let xdk_error: SdkGeneratorError = template_error.into(); + + match xdk_error { + SdkGeneratorError::TemplateError(err) => { + assert!(err.to_string().contains("Template")); + } + _ => panic!("Expected TemplateError"), + } +} + +#[test] +fn test_framework_error_creation() { + let framework_error = SdkGeneratorError::FrameworkError("Invalid configuration".to_string()); + + match framework_error { + SdkGeneratorError::FrameworkError(msg) => { + assert_eq!(msg, "Invalid configuration"); + } + _ => panic!("Expected FrameworkError"), + } +} + +#[test] +fn test_missing_field_error_creation() { + let missing_field_error = SdkGeneratorError::MissingField("operation_id".to_string()); + + match missing_field_error { + SdkGeneratorError::MissingField(field) => { + assert_eq!(field, "operation_id"); + } + _ => panic!("Expected MissingField error"), + } +} + +#[test] +fn test_other_error_creation() { + let other_error = SdkGeneratorError::Other("Custom error".to_string()); + + match other_error { + SdkGeneratorError::Other(msg) => { + assert_eq!(msg, "Custom error"); + } + _ => panic!("Expected Other error"), + } +} + +#[test] +fn test_string_conversion() { + let error: SdkGeneratorError = "Test error".into(); + + match error { + SdkGeneratorError::Other(msg) => { + assert_eq!(msg, "Test error"); + } + _ => panic!("Expected Other error from string conversion"), + } +} + +#[test] +fn test_error_display() { + let errors = vec![ + SdkGeneratorError::FrameworkError("Framework error".to_string()), + SdkGeneratorError::MissingField("field_name".to_string()), + SdkGeneratorError::Other("Other error".to_string()), + SdkGeneratorError::IoError(io::Error::new( + io::ErrorKind::PermissionDenied, + "Access denied", + )), + ]; + + for error in errors { + let display_string = format!("{}", error); + assert!(!display_string.is_empty()); + } +} + +#[test] +fn test_error_debug() { + let error = SdkGeneratorError::FrameworkError("Debug test".to_string()); + let debug_string = format!("{:?}", error); + assert!(debug_string.contains("FrameworkError")); + assert!(debug_string.contains("Debug test")); +} + +#[test] +fn test_result_type() { + fn success_function() -> Result { + Ok("Success".to_string()) + } + + fn error_function() -> Result { + Err(SdkGeneratorError::FrameworkError("Failed".to_string())) + } + + assert!(success_function().is_ok()); + assert_eq!(success_function().unwrap(), "Success"); + + assert!(error_function().is_err()); + match error_function().unwrap_err() { + SdkGeneratorError::FrameworkError(msg) => assert_eq!(msg, "Failed"), + _ => panic!("Expected FrameworkError"), + } +} + +#[test] +fn test_error_source() { + let io_error = io::Error::new(io::ErrorKind::NotFound, "Original error"); + let xdk_error: SdkGeneratorError = io_error.into(); + + // Test that the error chain is preserved + assert!(std::error::Error::source(&xdk_error).is_some()); +} + +#[test] +fn test_error_send_sync() { + fn assert_send() {} + fn assert_sync() {} + + assert_send::(); + assert_sync::(); +} diff --git a/xdk-lib/tests/integration_tests.rs b/xdk-lib/tests/integration_tests.rs new file mode 100644 index 00000000..48497349 --- /dev/null +++ b/xdk-lib/tests/integration_tests.rs @@ -0,0 +1,409 @@ +use minijinja::Environment; +use openapi::{Parameter, RefOrValue}; +use serde::Serialize; +use std::collections::HashMap; +use std::fs; +use tempfile::TempDir; +use xdk_lib::{ + Casing, + models::{OperationInfo, ParameterInfo, TagInfo}, + templates::render_template, + testing::generate_test_specifications, +}; + +#[derive(Serialize)] +struct TestContext { + tag: xdk_lib::models::TagInfo, + operations: Vec, +} + +#[test] +fn test_end_to_end_tag_processing() { + // Test the complete flow from tag words to different casing variants + let tag_words = vec!["community".to_string(), "notes".to_string()]; + + // Test different language configurations + let python_tag = TagInfo::new(&tag_words, Casing::Pascal, Casing::Snake, Casing::Snake); + let java_tag = TagInfo::new(&tag_words, Casing::Pascal, Casing::Pascal, Casing::Camel); + let csharp_tag = TagInfo::new(&tag_words, Casing::Pascal, Casing::Pascal, Casing::Pascal); + + // Python style + assert_eq!(python_tag.class_name, "CommunityNotes"); + assert_eq!(python_tag.import_name, "community_notes"); + assert_eq!(python_tag.property_name, "community_notes"); + + // Java style + assert_eq!(java_tag.class_name, "CommunityNotes"); + assert_eq!(java_tag.import_name, "CommunityNotes"); + assert_eq!(java_tag.property_name, "communityNotes"); + + // C# style + assert_eq!(csharp_tag.class_name, "CommunityNotes"); + assert_eq!(csharp_tag.import_name, "CommunityNotes"); + assert_eq!(csharp_tag.property_name, "CommunityNotes"); +} + +#[test] +fn test_end_to_end_parameter_processing() { + // Create OpenAPI parameters + let params = vec![ + RefOrValue::Value(Parameter { + name: Some("maxResults".to_string()), + r#in: Some("query".to_string()), + required: Some(false), + schema: None, + description: Some("Maximum number of results".to_string()), + }), + RefOrValue::Value(Parameter { + name: Some("userId".to_string()), + r#in: Some("path".to_string()), + required: Some(true), + schema: None, + description: None, + }), + RefOrValue::Value(Parameter { + name: Some("authToken".to_string()), + r#in: Some("header".to_string()), + required: Some(false), + schema: None, + description: Some("Authorization token".to_string()), + }), + ]; + + let parameters = Some(params); + + // Test different language parameter casing + let python_params = ParameterInfo::from_openapi_parameters(¶meters, Casing::Snake).unwrap(); + let java_params = ParameterInfo::from_openapi_parameters(¶meters, Casing::Camel).unwrap(); + let csharp_params = + ParameterInfo::from_openapi_parameters(¶meters, Casing::Pascal).unwrap(); + + // All should have 3 parameters + assert_eq!(python_params.len(), 3); + assert_eq!(java_params.len(), 3); + assert_eq!(csharp_params.len(), 3); + + // Find maxResults parameter and check casing + let max_results_python = python_params + .iter() + .find(|p| p.original_name == "maxResults") + .unwrap(); + let max_results_java = java_params + .iter() + .find(|p| p.original_name == "maxResults") + .unwrap(); + let max_results_csharp = csharp_params + .iter() + .find(|p| p.original_name == "maxResults") + .unwrap(); + + assert_eq!(max_results_python.variable_name, "max_results"); + assert_eq!(max_results_java.variable_name, "maxResults"); + assert_eq!(max_results_csharp.variable_name, "MaxResults"); +} + +#[test] +fn test_end_to_end_operation_processing() { + // Create test operation with parameters + let params = vec![ + ParameterInfo { + original_name: "max_results".to_string(), + variable_name: "max_results".to_string(), + location: "query".to_string(), + required: false, + param_type: "integer".to_string(), + description: Some("Maximum results".to_string()), + schema: None, + }, + ParameterInfo { + original_name: "next_token".to_string(), + variable_name: "next_token".to_string(), + location: "query".to_string(), + required: false, + param_type: "string".to_string(), + description: Some("Pagination token".to_string()), + schema: None, + }, + ]; + + let operation = OperationInfo { + class_name: "GetTweets".to_string(), + method_name: "get_tweets".to_string(), + method: "GET".to_string(), + path: "/tweets".to_string(), + description: Some("Retrieve tweets".to_string()), + summary: Some("Get tweets".to_string()), + security: None, + parameters: Some(params), + request_body: None, + responses: HashMap::new(), + }; + + // Test that operation can be used for test generation + let mut operations_by_tag = HashMap::new(); + operations_by_tag.insert("tweets".to_string(), vec![operation]); + + let test_specs = generate_test_specifications(&operations_by_tag).unwrap(); + let tweets_spec = test_specs.get("tweets").unwrap(); + + // Should detect pagination (has both token and limit params) + let method = &tweets_spec.structural_tests[0].methods[0]; + assert!(method.supports_pagination); + assert_eq!(method.method_name, "get_tweets"); + assert_eq!(method.class_name, "GetTweets"); + + // Should have pagination tests + assert_eq!(tweets_spec.pagination_tests.len(), 1); + let pagination_test = &tweets_spec.pagination_tests[0]; + assert_eq!(pagination_test.method_name, "get_tweets"); +} + +#[test] +fn test_end_to_end_template_rendering() { + // Create test data + let tag_info = TagInfo::new( + &["user".to_string(), "profile".to_string()], + Casing::Pascal, + Casing::Snake, + Casing::Snake, + ); + + let operation = OperationInfo { + class_name: "GetUserProfile".to_string(), + method_name: "get_user_profile".to_string(), + method: "GET".to_string(), + path: "/users/{id}/profile".to_string(), + description: Some("Get user profile".to_string()), + summary: None, + security: None, + parameters: Some(vec![ParameterInfo { + original_name: "userId".to_string(), + variable_name: "user_id".to_string(), + location: "path".to_string(), + required: true, + param_type: "string".to_string(), + description: Some("User ID".to_string()), + schema: None, + }]), + request_body: None, + responses: HashMap::new(), + }; + + let context = TestContext { + tag: tag_info, + operations: vec![operation], + }; + + // Create template + let mut env = Environment::new(); + let template = r#" +# {{ tag.class_name }} Client + +Class: {{ tag.class_name }} +Import: {{ tag.import_name }} +Property: {{ tag.property_name }} + +## Operations + +{% for operation in operations %} +### {{ operation.method_name }} +- Method: {{ operation.method }} +- Path: {{ operation.path }} +- Class: {{ operation.class_name }} +{% if operation.parameters %} +Parameters: +{% for param in operation.parameters %} + - {{ param.variable_name }} ({{ param.param_type }}, {{ param.location }}){% if param.required %} *required*{% endif %} +{% endfor %} +{% endif %} +{% endfor %} +"#; + + env.add_template("test_client", template).unwrap(); + + let result = render_template(&env, "test_client", &context).unwrap(); + + // Verify template rendered correctly + assert!(result.contains("# UserProfile Client")); + assert!(result.contains("Class: UserProfile")); + assert!(result.contains("Import: user_profile")); + assert!(result.contains("Property: user_profile")); + assert!(result.contains("### get_user_profile")); + assert!(result.contains("Method: GET")); + assert!(result.contains("Path: /users/{id}/profile")); + assert!(result.contains("Class: GetUserProfile")); + assert!(result.contains("user_id (string, path) *required*")); +} + +#[test] +fn test_end_to_end_file_generation() { + use std::io::Write; + + // Create temporary directory for test output + let temp_dir = TempDir::new().unwrap(); + let output_dir = temp_dir.path(); + + // Create test data + let tag_info = TagInfo::new( + &["users".to_string()], + Casing::Pascal, + Casing::Snake, + Casing::Snake, + ); + + let operation = OperationInfo { + class_name: "GetUsers".to_string(), + method_name: "get_users".to_string(), + method: "GET".to_string(), + path: "/users".to_string(), + description: Some("List users".to_string()), + summary: None, + security: None, + parameters: None, + request_body: None, + responses: HashMap::new(), + }; + + let context = TestContext { + tag: tag_info, + operations: vec![operation], + }; + + // Create simple template + let mut env = Environment::new(); + env.add_template("client", "class {{ tag.class_name }}Client:\n def {{ operations[0].method_name }}(self):\n pass").unwrap(); + + // Render and write file + let rendered = render_template(&env, "client", &context).unwrap(); + let file_path = output_dir.join("users_client.py"); + + let mut file = fs::File::create(&file_path).unwrap(); + file.write_all(rendered.as_bytes()).unwrap(); + + // Verify file was created and contains expected content + let content = fs::read_to_string(&file_path).unwrap(); + assert!(content.contains("class UsersClient:")); + assert!(content.contains("def get_users(self):")); +} + +#[test] +fn test_end_to_end_multiple_languages() { + // Test that the same operation can be processed for different languages + let operation_id_words = vec!["get".to_string(), "user".to_string(), "profile".to_string()]; + let tag_words = vec!["user".to_string(), "management".to_string()]; + + // Simulate processing for Python + let python_operation_method = Casing::Snake.convert_words(&operation_id_words); + let python_operation_class = Casing::Pascal.convert_words(&operation_id_words); + let python_tag = TagInfo::new(&tag_words, Casing::Pascal, Casing::Snake, Casing::Snake); + + // Simulate processing for Java + let java_operation_method = Casing::Camel.convert_words(&operation_id_words); + let java_operation_class = Casing::Pascal.convert_words(&operation_id_words); + let java_tag = TagInfo::new(&tag_words, Casing::Pascal, Casing::Pascal, Casing::Camel); + + // Simulate processing for C# + let csharp_operation_method = Casing::Pascal.convert_words(&operation_id_words); + let csharp_operation_class = Casing::Pascal.convert_words(&operation_id_words); + let csharp_tag = TagInfo::new(&tag_words, Casing::Pascal, Casing::Pascal, Casing::Pascal); + + // Verify Python style + assert_eq!(python_operation_method, "get_user_profile"); + assert_eq!(python_operation_class, "GetUserProfile"); + assert_eq!(python_tag.import_name, "user_management"); + assert_eq!(python_tag.property_name, "user_management"); + + // Verify Java style + assert_eq!(java_operation_method, "getUserProfile"); + assert_eq!(java_operation_class, "GetUserProfile"); + assert_eq!(java_tag.import_name, "UserManagement"); + assert_eq!(java_tag.property_name, "userManagement"); + + // Verify C# style + assert_eq!(csharp_operation_method, "GetUserProfile"); + assert_eq!(csharp_operation_class, "GetUserProfile"); + assert_eq!(csharp_tag.import_name, "UserManagement"); + assert_eq!(csharp_tag.property_name, "UserManagement"); +} + +#[test] +fn test_end_to_end_error_handling() { + // Test error scenarios throughout the pipeline + + // Test invalid template + let mut env = Environment::new(); + env.add_template("invalid", "{{ invalid_variable.nonexistent_field }}") + .unwrap(); + + #[derive(Serialize)] + struct EmptyContext {} + + let result = render_template(&env, "invalid", &EmptyContext {}); + assert!(result.is_err()); + + // Test empty operations for test generation + let empty_operations = HashMap::new(); + let test_specs = generate_test_specifications(&empty_operations).unwrap(); + assert!(test_specs.is_empty()); + + // Test parameter processing with empty parameters + let result = ParameterInfo::from_openapi_parameters(&None, Casing::Snake); + assert!(result.is_none()); + + let empty_params = Some(vec![]); + let result = ParameterInfo::from_openapi_parameters(&empty_params, Casing::Snake).unwrap(); + assert!(result.is_empty()); +} + +#[test] +fn test_template_rendering_functionality() { + use minijinja::Environment; + use serde::Serialize; + + #[derive(Serialize)] + struct TestTemplateContext { + name: String, + count: i32, + } + + let mut env = Environment::new(); + env.add_template("test", "Hello {{ name }}! Count: {{ count }}") + .unwrap(); + + let context = TestTemplateContext { + name: "World".to_string(), + count: 42, + }; + + let result = render_template(&env, "test", &context).unwrap(); + assert_eq!(result, "Hello World! Count: 42"); +} + +#[test] +fn test_template_rendering_with_tag_info() { + use minijinja::Environment; + + let mut env = Environment::new(); + env.add_template( + "tag_test", + "Class: {{ tag.class_name }}, Import: {{ tag.import_name }}", + ) + .unwrap(); + + #[derive(serde::Serialize)] + struct TagContext { + tag: TagInfo, + } + + let tag_info = TagInfo::new( + &["user".to_string(), "profile".to_string()], + Casing::Pascal, + Casing::Snake, + Casing::Snake, + ); + + let context = TagContext { tag: tag_info }; + + let result = render_template(&env, "tag_test", &context).unwrap(); + assert_eq!(result, "Class: UserProfile, Import: user_profile"); +} diff --git a/xdk-lib/tests/lib.rs b/xdk-lib/tests/lib.rs new file mode 100644 index 00000000..eaea61f4 --- /dev/null +++ b/xdk-lib/tests/lib.rs @@ -0,0 +1,19 @@ +// XDK Lib Comprehensive Test Suite +// +// This test suite covers all major functionality of the xdk-lib crate including: +// - Casing conversions and transformations +// - Data model creation and manipulation +// - Parameter processing with language-specific casing +// - Template rendering and generation +// - Test specification generation +// - Error handling and edge cases +// - End-to-end integration scenarios + +mod casing_tests; +mod error_tests; +mod integration_tests; +mod models_tests; +mod testing_tests; + +// Re-export for convenience in other tests +pub use xdk_lib::*; diff --git a/xdk-lib/tests/models_tests.rs b/xdk-lib/tests/models_tests.rs new file mode 100644 index 00000000..51ad165d --- /dev/null +++ b/xdk-lib/tests/models_tests.rs @@ -0,0 +1,261 @@ +use openapi::{Parameter, RefOrValue}; +use std::collections::HashMap; +use xdk_lib::{ + Casing, + models::{Metadata, OperationGroup, OperationInfo, ParameterInfo, TagInfo}, +}; + +#[test] +fn test_operation_info_with_casing() { + let operation = OperationInfo { + class_name: String::new(), + method_name: String::new(), + method: "GET".to_string(), + path: "/users".to_string(), + description: Some("Get users".to_string()), + summary: Some("Retrieve users".to_string()), + security: None, + parameters: None, + request_body: None, + responses: HashMap::new(), + }; + + let updated_operation = operation.with_casing("get_users".to_string(), "GetUsers".to_string()); + + assert_eq!(updated_operation.method_name, "get_users"); + assert_eq!(updated_operation.class_name, "GetUsers"); + assert_eq!(updated_operation.method, "GET"); + assert_eq!(updated_operation.path, "/users"); +} + +#[test] +fn test_tag_info_creation() { + let tag_info = TagInfo { + original: vec!["user".to_string(), "profile".to_string()], + class_name: "UserProfile".to_string(), + import_name: "user_profile".to_string(), + property_name: "user_profile".to_string(), + display_name: "User Profile".to_string(), + }; + + assert_eq!(tag_info.original, vec!["user", "profile"]); + assert_eq!(tag_info.class_name, "UserProfile"); + assert_eq!(tag_info.import_name, "user_profile"); + assert_eq!(tag_info.property_name, "user_profile"); + assert_eq!(tag_info.display_name, "User Profile"); +} + +#[test] +fn test_parameter_info_structure() { + let param_info = ParameterInfo { + original_name: "maxResults".to_string(), + variable_name: "max_results".to_string(), + location: "query".to_string(), + required: false, + param_type: "integer".to_string(), + description: Some("Maximum number of results".to_string()), + schema: None, + }; + + assert_eq!(param_info.original_name, "maxResults"); + assert_eq!(param_info.variable_name, "max_results"); + assert_eq!(param_info.location, "query"); + assert!(!param_info.required); + assert_eq!(param_info.param_type, "integer"); + assert_eq!( + param_info.description, + Some("Maximum number of results".to_string()) + ); +} + +#[test] +fn test_operation_group_structure() { + let operation = OperationInfo { + class_name: "GetUser".to_string(), + method_name: "get_user".to_string(), + method: "GET".to_string(), + path: "/users/{id}".to_string(), + description: None, + summary: None, + security: None, + parameters: None, + request_body: None, + responses: HashMap::new(), + }; + + let metadata = Metadata { + normalized_operation_id: vec!["get".to_string(), "user".to_string()], + }; + + let operation_group = OperationGroup { + operation, + metadata, + raw_parameters: None, + }; + + assert_eq!(operation_group.operation.method_name, "get_user"); + assert_eq!( + operation_group.metadata.normalized_operation_id, + vec!["get", "user"] + ); + assert!(operation_group.raw_parameters.is_none()); +} + +#[test] +fn test_parameter_info_serialization() { + use serde_json; + + let param_info = ParameterInfo { + original_name: "userId".to_string(), + variable_name: "user_id".to_string(), + location: "path".to_string(), + required: true, + param_type: "string".to_string(), + description: Some("User identifier".to_string()), + schema: None, + }; + + let json = serde_json::to_string(¶m_info).expect("Serialization should work"); + assert!(json.contains("userId")); + assert!(json.contains("user_id")); + assert!(json.contains("path")); + assert!(json.contains("true")); +} + +#[test] +fn test_tag_info_serialization() { + use serde_json; + + let tag_info = TagInfo { + original: vec!["community".to_string(), "notes".to_string()], + class_name: "CommunityNotes".to_string(), + import_name: "community_notes".to_string(), + property_name: "community_notes".to_string(), + display_name: "Community Notes".to_string(), + }; + + let json = serde_json::to_string(&tag_info).expect("Serialization should work"); + assert!(json.contains("CommunityNotes")); + assert!(json.contains("community_notes")); + assert!(json.contains("Community Notes")); +} + +#[test] +fn test_tag_info_factory_function() { + let tag_words = vec!["community".to_string(), "notes".to_string()]; + + // Test Python-style casing + let python_tag = TagInfo::new( + &tag_words, + Casing::Pascal, // class_casing + Casing::Snake, // import_casing + Casing::Snake, // property_casing + ); + + assert_eq!(python_tag.original, vec!["community", "notes"]); + assert_eq!(python_tag.class_name, "CommunityNotes"); + assert_eq!(python_tag.import_name, "community_notes"); + assert_eq!(python_tag.property_name, "community_notes"); + assert_eq!(python_tag.display_name, "community notes"); + + // Test Java-style casing + let java_tag = TagInfo::new( + &tag_words, + Casing::Pascal, // class_casing + Casing::Pascal, // import_casing + Casing::Camel, // property_casing + ); + + assert_eq!(java_tag.class_name, "CommunityNotes"); + assert_eq!(java_tag.import_name, "CommunityNotes"); + assert_eq!(java_tag.property_name, "communityNotes"); +} + +#[test] +fn test_tag_info_factory_with_single_word() { + let tag_words = vec!["tweets".to_string()]; + + let tag_info = TagInfo::new(&tag_words, Casing::Pascal, Casing::Snake, Casing::Snake); + + assert_eq!(tag_info.class_name, "Tweets"); + assert_eq!(tag_info.import_name, "tweets"); + assert_eq!(tag_info.property_name, "tweets"); + assert_eq!(tag_info.display_name, "tweets"); +} + +#[test] +fn test_parameter_info_from_openapi_basic() { + let param = Parameter { + name: Some("maxResults".to_string()), + r#in: Some("query".to_string()), + description: Some("Maximum number of results".to_string()), + required: Some(false), + schema: None, // Simplified for testing + }; + + let parameters = Some(vec![RefOrValue::Value(param)]); + + let processed = ParameterInfo::from_openapi_parameters(¶meters, Casing::Snake); + assert!(processed.is_some()); + + let params = processed.unwrap(); + assert_eq!(params.len(), 1); + assert_eq!(params[0].original_name, "maxResults"); + assert_eq!(params[0].variable_name, "max_results"); + assert_eq!(params[0].location, "query"); + assert!(!params[0].required); + assert_eq!(params[0].param_type, "any"); // Default when no schema +} + +#[test] +fn test_parameter_info_casing_variants() { + let param = Parameter { + name: Some("maxResults".to_string()), + r#in: Some("query".to_string()), + description: Some("Maximum number of results".to_string()), + required: Some(false), + schema: None, + }; + + let parameters = Some(vec![RefOrValue::Value(param)]); + + // Test with different casings + let snake_case_result = + ParameterInfo::from_openapi_parameters(¶meters, Casing::Snake).unwrap(); + assert_eq!(snake_case_result[0].variable_name, "max_results"); + + let camel_case_result = + ParameterInfo::from_openapi_parameters(¶meters, Casing::Camel).unwrap(); + assert_eq!(camel_case_result[0].variable_name, "maxResults"); + + let pascal_case_result = + ParameterInfo::from_openapi_parameters(¶meters, Casing::Pascal).unwrap(); + assert_eq!(pascal_case_result[0].variable_name, "MaxResults"); +} + +#[test] +fn test_parameter_info_path_param_required() { + let param = Parameter { + name: Some("userId".to_string()), + r#in: Some("path".to_string()), + description: Some("User ID".to_string()), + required: Some(false), // Even if set to false, path params should be required + schema: None, + }; + + let parameters = Some(vec![RefOrValue::Value(param)]); + let processed = ParameterInfo::from_openapi_parameters(¶meters, Casing::Snake).unwrap(); + + // Path parameters should always be required + assert!(processed[0].required); +} + +#[test] +fn test_parameter_info_empty_parameters() { + let result = ParameterInfo::from_openapi_parameters(&None, Casing::Snake); + assert!(result.is_none()); + + let empty_params = Some(vec![]); + let result = ParameterInfo::from_openapi_parameters(&empty_params, Casing::Snake).unwrap(); + assert_eq!(result.len(), 0); +} diff --git a/xdk-lib/tests/testing_tests.rs b/xdk-lib/tests/testing_tests.rs new file mode 100644 index 00000000..62397d30 --- /dev/null +++ b/xdk-lib/tests/testing_tests.rs @@ -0,0 +1,357 @@ +use std::collections::HashMap; +use xdk_lib::models::{OperationInfo, ParameterInfo}; +use xdk_lib::testing::{ + ContractTest, MethodSignature, MockScenario, PaginationTest, TestParameter, TestSpecification, + generate_test_specifications, +}; + +fn create_test_operation( + method_name: &str, + class_name: &str, + method: &str, + path: &str, + parameters: Option>, +) -> OperationInfo { + OperationInfo { + class_name: class_name.to_string(), + method_name: method_name.to_string(), + method: method.to_string(), + path: path.to_string(), + description: Some(format!("{} operation", method_name)), + summary: Some(format!("{} summary", method_name)), + security: None, + parameters, + request_body: None, + responses: HashMap::new(), + } +} + +fn create_test_parameter( + original_name: &str, + variable_name: &str, + location: &str, + required: bool, + param_type: &str, +) -> ParameterInfo { + ParameterInfo { + original_name: original_name.to_string(), + variable_name: variable_name.to_string(), + location: location.to_string(), + required, + param_type: param_type.to_string(), + description: Some(format!("{} parameter", original_name)), + schema: None, + } +} + +#[test] +fn test_generate_test_specifications_basic() { + let mut operations_by_tag = HashMap::new(); + + let operation = create_test_operation( + "get_users", + "GetUsers", + "GET", + "/users", + Some(vec![create_test_parameter( + "maxResults", + "max_results", + "query", + false, + "integer", + )]), + ); + + operations_by_tag.insert("users".to_string(), vec![operation]); + + let result = generate_test_specifications(&operations_by_tag).unwrap(); + + assert_eq!(result.len(), 1); + let test_spec = result.get("users").unwrap(); + + // Check structural tests + assert_eq!(test_spec.structural_tests.len(), 1); + let structural_test = &test_spec.structural_tests[0]; + assert_eq!(structural_test.methods.len(), 1); + + let method = &structural_test.methods[0]; + assert_eq!(method.method_name, "get_users"); + assert_eq!(method.class_name, "GetUsers"); + assert_eq!(method.return_type, "GetUsersResponse"); + assert!(!method.supports_pagination); + + // Check contract tests + assert_eq!(test_spec.contract_tests.len(), 1); + let contract_test = &test_spec.contract_tests[0]; + assert_eq!(contract_test.method_name, "get_users"); + assert_eq!(contract_test.class_name, "GetUsers"); + assert_eq!(contract_test.method, "GET"); + assert_eq!(contract_test.path, "/users"); + + // Check mock scenarios + assert_eq!(test_spec.mock_scenarios.len(), 3); // success, not_found, rate_limit + let success_scenario = test_spec + .mock_scenarios + .iter() + .find(|s| s.scenario_name == "success") + .unwrap(); + assert_eq!(success_scenario.method_name, "get_users"); + assert_eq!(success_scenario.status_code, 200); +} + +#[test] +fn test_generate_test_specifications_with_pagination() { + let mut operations_by_tag = HashMap::new(); + + let operation = create_test_operation( + "get_tweets", + "GetTweets", + "GET", + "/tweets", + Some(vec![ + create_test_parameter( + "pagination_token", + "pagination_token", + "query", + false, + "string", + ), + create_test_parameter("max_results", "max_results", "query", false, "integer"), + create_test_parameter("query", "query", "query", true, "string"), + ]), + ); + + operations_by_tag.insert("tweets".to_string(), vec![operation]); + + let result = generate_test_specifications(&operations_by_tag).unwrap(); + let test_spec = result.get("tweets").unwrap(); + + // Should detect pagination support + let method = &test_spec.structural_tests[0].methods[0]; + assert!(method.supports_pagination); + + // Should have pagination tests + assert_eq!(test_spec.pagination_tests.len(), 1); + let pagination_test = &test_spec.pagination_tests[0]; + assert_eq!(pagination_test.method_name, "get_tweets"); + assert_eq!( + pagination_test.token_param, + Some("pagination_token".to_string()) + ); + assert_eq!( + pagination_test.max_results_param, + Some("max_results".to_string()) + ); +} + +#[test] +fn test_generate_test_specifications_multiple_operations() { + let mut operations_by_tag = HashMap::new(); + + let get_operation = create_test_operation( + "get_user", + "GetUser", + "GET", + "/users/{id}", + Some(vec![create_test_parameter( + "id", "id", "path", true, "string", + )]), + ); + + let post_operation = create_test_operation("create_user", "CreateUser", "POST", "/users", None); + + operations_by_tag.insert("users".to_string(), vec![get_operation, post_operation]); + + let result = generate_test_specifications(&operations_by_tag).unwrap(); + let test_spec = result.get("users").unwrap(); + + // Should have 2 methods in structural tests + assert_eq!(test_spec.structural_tests[0].methods.len(), 2); + + // Should have 2 contract tests + assert_eq!(test_spec.contract_tests.len(), 2); + + // Should have 6 mock scenarios (3 per operation) + assert_eq!(test_spec.mock_scenarios.len(), 6); +} + +#[test] +fn test_generate_test_specifications_multiple_tags() { + let mut operations_by_tag = HashMap::new(); + + let users_operation = create_test_operation("get_users", "GetUsers", "GET", "/users", None); + + let tweets_operation = create_test_operation("get_tweets", "GetTweets", "GET", "/tweets", None); + + operations_by_tag.insert("users".to_string(), vec![users_operation]); + operations_by_tag.insert("tweets".to_string(), vec![tweets_operation]); + + let result = generate_test_specifications(&operations_by_tag).unwrap(); + + assert_eq!(result.len(), 2); + assert!(result.contains_key("users")); + assert!(result.contains_key("tweets")); +} + +#[test] +fn test_test_parameter_structure() { + let test_param = TestParameter { + name: "maxResults".to_string(), + variable_name: "max_results".to_string(), + param_type: "integer".to_string(), + location: "query".to_string(), + required: false, + description: Some("Maximum number of results".to_string()), + }; + + assert_eq!(test_param.name, "maxResults"); + assert_eq!(test_param.variable_name, "max_results"); + assert_eq!(test_param.param_type, "integer"); + assert_eq!(test_param.location, "query"); + assert!(!test_param.required); +} + +#[test] +fn test_method_signature_structure() { + let method_sig = MethodSignature { + method_name: "get_user".to_string(), + class_name: "GetUser".to_string(), + required_params: vec![], + optional_params: vec![], + return_type: "GetUserResponse".to_string(), + supports_pagination: false, + }; + + assert_eq!(method_sig.method_name, "get_user"); + assert_eq!(method_sig.class_name, "GetUser"); + assert_eq!(method_sig.return_type, "GetUserResponse"); + assert!(!method_sig.supports_pagination); +} + +#[test] +fn test_contract_test_structure() { + let contract_test = ContractTest { + method_name: "get_user".to_string(), + class_name: "GetUser".to_string(), + method: "GET".to_string(), + path: "/users/{id}".to_string(), + required_params: vec![], + optional_params: vec![], + request_body_schema: None, + response_schema: xdk_lib::testing::ResponseSchema { + status_code: 200, + content_type: "application/json".to_string(), + expected_fields: vec![], + }, + security_requirements: vec![], + }; + + assert_eq!(contract_test.method_name, "get_user"); + assert_eq!(contract_test.class_name, "GetUser"); + assert_eq!(contract_test.method, "GET"); + assert_eq!(contract_test.path, "/users/{id}"); + assert_eq!(contract_test.response_schema.status_code, 200); +} + +#[test] +fn test_pagination_test_structure() { + let pagination_test = PaginationTest { + method_name: "get_tweets".to_string(), + required_params: vec![], + token_param: Some("pagination_token".to_string()), + max_results_param: Some("max_results".to_string()), + next_token_field: Some("next_token".to_string()), + data_field: "data".to_string(), + }; + + assert_eq!(pagination_test.method_name, "get_tweets"); + assert_eq!( + pagination_test.token_param, + Some("pagination_token".to_string()) + ); + assert_eq!( + pagination_test.max_results_param, + Some("max_results".to_string()) + ); +} + +#[test] +fn test_mock_scenario_structure() { + let mock_scenario = MockScenario { + method_name: "get_user".to_string(), + scenario_name: "success".to_string(), + status_code: 200, + response_body: serde_json::json!({"id": "123", "name": "John Doe"}), + request_params: std::collections::HashMap::new(), + description: "Successful user retrieval".to_string(), + }; + + assert_eq!(mock_scenario.method_name, "get_user"); + assert_eq!(mock_scenario.scenario_name, "success"); + assert_eq!(mock_scenario.status_code, 200); + assert_eq!(mock_scenario.description, "Successful user retrieval"); +} + +#[test] +fn test_test_specification_serialization() { + use serde_json; + + let test_spec = TestSpecification { + structural_tests: vec![], + contract_tests: vec![], + pagination_tests: vec![], + mock_scenarios: vec![], + }; + + let json = serde_json::to_string(&test_spec).expect("Serialization should work"); + assert!(json.contains("structural_tests")); + assert!(json.contains("contract_tests")); + assert!(json.contains("pagination_tests")); + assert!(json.contains("mock_scenarios")); +} + +#[test] +fn test_pagination_detection_edge_cases() { + // Test operation with only token param (no limit) - should not support pagination + let operation_token_only = create_test_operation( + "get_items", + "GetItems", + "GET", + "/items", + Some(vec![create_test_parameter( + "next_token", + "next_token", + "query", + false, + "string", + )]), + ); + + // Test operation with only limit param (no token) - should not support pagination + let operation_limit_only = create_test_operation( + "get_data", + "GetData", + "GET", + "/data", + Some(vec![create_test_parameter( + "limit", "limit", "query", false, "integer", + )]), + ); + + let mut operations_by_tag = HashMap::new(); + operations_by_tag.insert( + "test".to_string(), + vec![operation_token_only, operation_limit_only], + ); + + let result = generate_test_specifications(&operations_by_tag).unwrap(); + let test_spec = result.get("test").unwrap(); + + // Neither operation should support pagination + for method in &test_spec.structural_tests[0].methods { + assert!(!method.supports_pagination); + } + + // Should have no pagination tests + assert_eq!(test_spec.pagination_tests.len(), 0); +} diff --git a/xdk-openapi/src/lib.rs b/xdk-openapi/src/lib.rs index 884ed033..ac302849 100644 --- a/xdk-openapi/src/lib.rs +++ b/xdk-openapi/src/lib.rs @@ -161,23 +161,19 @@ mod tests { // Should be able to access anyOf schemas in components if let Some(components) = &openapi.components { if let Some(schemas) = &components.schemas { - if let Some(any_of_schema) = schemas.get("TestSchemaAnyOf") { - if let Schema::AnyOf(any_of) = any_of_schema { - assert_eq!(any_of.any_of.len(), 3); - println!( - "Successfully parsed anyOf schema with {} variants", - any_of.any_of.len() - ); - } + if let Some(Schema::AnyOf(any_of)) = schemas.get("TestSchemaAnyOf") { + assert_eq!(any_of.any_of.len(), 3); + println!( + "Successfully parsed anyOf schema with {} variants", + any_of.any_of.len() + ); } - if let Some(all_of_schema) = schemas.get("TestSchemaAllOf") { - if let Schema::AllOf(all_of) = all_of_schema { - assert_eq!(all_of.all_of.len(), 3); - println!( - "Successfully parsed allOf schema with {} variants", - all_of.all_of.len() - ); - } + if let Some(Schema::AllOf(all_of)) = schemas.get("TestSchemaAllOf") { + assert_eq!(all_of.all_of.len(), 3); + println!( + "Successfully parsed allOf schema with {} variants", + all_of.all_of.len() + ); } } } diff --git a/xdk/python/README.md b/xdk/python/README.md index 54ccd05f..725eb9c1 100644 --- a/xdk/python/README.md +++ b/xdk/python/README.md @@ -27,14 +27,14 @@ client = Client( ) # Use the client to interact with the X API -# For example, to get tweets: -tweets = client.tweets.get_tweets(ids=["1234567890"]) +# For example, to get posts: +posts = client.posts.get(ids=["1234567890"]) -# To search for tweets: -search_results = client.tweets.tweets_recent_search(query="python") +# To search for posts: +search_results = client.posts.recent_search(query="python") -# To post a tweet: -tweet = client.tweets.post_tweets(tweet_data={"text": "Hello, world!"}) +# To post a post: +post = client.posts.create(post_data={"text": "Hello, world!"}) ``` ## Features diff --git a/xdk/python/tests/aaasubscriptions/test_contracts.py b/xdk/python/tests/aaasubscriptions/test_contracts.py index 11d86ccd..43c0f0e7 100644 --- a/xdk/python/tests/aaasubscriptions/test_contracts.py +++ b/xdk/python/tests/aaasubscriptions/test_contracts.py @@ -1,8 +1,8 @@ """ -Auto-generated contract tests for AAASubscriptions client. +Auto-generated contract tests for {"class_name": "Aaasubscriptions", "display_name": "aaasubscriptions", "import_name": "aaasubscriptions", "original": ["aaasubscriptions"], "property_name": "aaasubscriptions"} client. This module contains tests that validate the request/response contracts -of the AAASubscriptions client against the OpenAPI specification. +of the {"class_name": "Aaasubscriptions", "display_name": "aaasubscriptions", "import_name": "aaasubscriptions", "original": ["aaasubscriptions"], "property_name": "aaasubscriptions"} client against the OpenAPI specification. Generated automatically - do not edit manually. """ @@ -10,12 +10,12 @@ import pytest import json from unittest.mock import Mock, patch -from xdk.aaasubscriptions.client import AAASubscriptionsClient +from xdk.aaasubscriptions.client import AaasubscriptionsClient from xdk import Client -class TestAAASubscriptionsContracts: - """Test the API contracts of AAASubscriptionsClient.""" +class TestAaasubscriptionsContracts: + """Test the API contracts of AaasubscriptionsClient.""" def setup_class(self): diff --git a/xdk/python/tests/aaasubscriptions/test_generic.py b/xdk/python/tests/aaasubscriptions/test_generic.py index c08755d9..96f32412 100644 --- a/xdk/python/tests/aaasubscriptions/test_generic.py +++ b/xdk/python/tests/aaasubscriptions/test_generic.py @@ -1,5 +1,5 @@ """ -Auto-generated generic tests for AAASubscriptions client. +Auto-generated generic tests for {"class_name": "Aaasubscriptions", "display_name": "aaasubscriptions", "import_name": "aaasubscriptions", "original": ["aaasubscriptions"], "property_name": "aaasubscriptions"} client. This module contains general tests that validate the overall client functionality, imports, and error handling that don't need to be @@ -11,12 +11,12 @@ import pytest import inspect from unittest.mock import Mock, patch -from xdk.aaasubscriptions.client import AAASubscriptionsClient +from xdk.aaasubscriptions.client import AaasubscriptionsClient from xdk import Client -class TestAAASubscriptionsGeneric: - """Generic tests for AAASubscriptionsClient.""" +class TestAaasubscriptionsGeneric: + """Generic tests for AaasubscriptionsClient.""" def setup_class(self): @@ -26,16 +26,16 @@ def setup_class(self): def test_client_exists(self): - """Test that AAASubscriptionsClient class exists and is importable.""" - assert AAASubscriptionsClient is not None - assert hasattr(AAASubscriptionsClient, "__name__") - assert AAASubscriptionsClient.__name__ == "AAASubscriptionsClient" + """Test that AaasubscriptionsClient class exists and is importable.""" + assert AaasubscriptionsClient is not None + assert hasattr(AaasubscriptionsClient, "__name__") + assert AaasubscriptionsClient.__name__ == "AaasubscriptionsClient" def test_client_initialization(self): - """Test that AAASubscriptionsClient can be initialized properly.""" + """Test that AaasubscriptionsClient can be initialized properly.""" assert self.aaasubscriptions_client is not None - assert isinstance(self.aaasubscriptions_client, AAASubscriptionsClient) + assert isinstance(self.aaasubscriptions_client, AaasubscriptionsClient) def test_imports_work(self): @@ -62,9 +62,9 @@ def test_error_responses_handling(self): # Get first available method for testing error handling client_methods = [ name - for name in dir(AAASubscriptionsClient) + for name in dir(AaasubscriptionsClient) if not name.startswith("_") - and callable(getattr(AAASubscriptionsClient, name)) + and callable(getattr(AaasubscriptionsClient, name)) ] if client_methods: method_name = client_methods[0] @@ -99,19 +99,19 @@ def test_client_has_expected_base_functionality(self): ] assert ( len(public_methods) > 0 - ), f"AAASubscriptionsClient should have at least one public method" + ), f"AaasubscriptionsClient should have at least one public method" def test_client_method_signatures_are_valid(self): """Test that all client methods have valid Python signatures.""" public_methods = [ name - for name in dir(AAASubscriptionsClient) + for name in dir(AaasubscriptionsClient) if not name.startswith("_") - and callable(getattr(AAASubscriptionsClient, name)) + and callable(getattr(AaasubscriptionsClient, name)) ] for method_name in public_methods: - method = getattr(AAASubscriptionsClient, method_name) + method = getattr(AaasubscriptionsClient, method_name) # Should be able to get signature without error try: sig = inspect.signature(method) diff --git a/xdk/python/tests/aaasubscriptions/test_structure.py b/xdk/python/tests/aaasubscriptions/test_structure.py index 99ebfe46..2a811455 100644 --- a/xdk/python/tests/aaasubscriptions/test_structure.py +++ b/xdk/python/tests/aaasubscriptions/test_structure.py @@ -1,8 +1,8 @@ """ -Auto-generated structural tests for AAASubscriptions client. +Auto-generated structural tests for {"class_name": "Aaasubscriptions", "display_name": "aaasubscriptions", "import_name": "aaasubscriptions", "original": ["aaasubscriptions"], "property_name": "aaasubscriptions"} client. This module contains tests that validate the structure and API surface -of the AAASubscriptions client. These tests ensure that all expected methods +of the {"class_name": "Aaasubscriptions", "display_name": "aaasubscriptions", "import_name": "aaasubscriptions", "original": ["aaasubscriptions"], "property_name": "aaasubscriptions"} client. These tests ensure that all expected methods exist and have the correct signatures. Generated automatically - do not edit manually. @@ -11,12 +11,12 @@ import pytest import inspect from typing import get_type_hints -from xdk.aaasubscriptions.client import AAASubscriptionsClient +from xdk.aaasubscriptions.client import AaasubscriptionsClient from xdk import Client -class TestAAASubscriptionsStructure: - """Test the structure of AAASubscriptionsClient.""" +class TestAaasubscriptionsStructure: + """Test the structure of AaasubscriptionsClient.""" def setup_class(self): @@ -29,11 +29,11 @@ def test_create_account_activity_subscription_exists(self): """Test that create_account_activity_subscription method exists with correct signature.""" # Check method exists method = getattr( - AAASubscriptionsClient, "create_account_activity_subscription", None + AaasubscriptionsClient, "create_account_activity_subscription", None ) assert ( method is not None - ), f"Method create_account_activity_subscription does not exist on AAASubscriptionsClient" + ), f"Method create_account_activity_subscription does not exist on AaasubscriptionsClient" # Check method is callable assert callable(method), f"create_account_activity_subscription is not callable" # Check method signature @@ -66,7 +66,7 @@ def test_create_account_activity_subscription_exists(self): def test_create_account_activity_subscription_return_annotation(self): """Test that create_account_activity_subscription has proper return type annotation.""" - method = getattr(AAASubscriptionsClient, "create_account_activity_subscription") + method = getattr(AaasubscriptionsClient, "create_account_activity_subscription") sig = inspect.signature(method) # Check return annotation exists assert ( @@ -81,8 +81,8 @@ def test_all_expected_methods_exist(self): ] for expected_method in expected_methods: assert hasattr( - AAASubscriptionsClient, expected_method - ), f"Expected method '{expected_method}' not found on AAASubscriptionsClient" + AaasubscriptionsClient, expected_method + ), f"Expected method '{expected_method}' not found on AaasubscriptionsClient" assert callable( - getattr(AAASubscriptionsClient, expected_method) + getattr(AaasubscriptionsClient, expected_method) ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/tests/account_activity/test_contracts.py b/xdk/python/tests/account_activity/test_contracts.py index 2f21bd2d..6661ec6d 100644 --- a/xdk/python/tests/account_activity/test_contracts.py +++ b/xdk/python/tests/account_activity/test_contracts.py @@ -1,8 +1,8 @@ """ -Auto-generated contract tests for Account_Activity client. +Auto-generated contract tests for {"class_name": "AccountActivity", "display_name": "account activity", "import_name": "account_activity", "original": ["account", "activity"], "property_name": "account_activity"} client. This module contains tests that validate the request/response contracts -of the Account_Activity client against the OpenAPI specification. +of the {"class_name": "AccountActivity", "display_name": "account activity", "import_name": "account_activity", "original": ["account", "activity"], "property_name": "account_activity"} client against the OpenAPI specification. Generated automatically - do not edit manually. """ @@ -24,8 +24,8 @@ def setup_class(self): self.account_activity_client = getattr(self.client, "account_activity") - def test_get_account_activity_subscriptions_request_structure(self): - """Test get_account_activity_subscriptions request structure.""" + def test_get_subscriptions_request_structure(self): + """Test get_subscriptions request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -42,9 +42,7 @@ def test_get_account_activity_subscriptions_request_structure(self): # Add request body if required # Call the method try: - method = getattr( - self.account_activity_client, "get_account_activity_subscriptions" - ) + method = getattr(self.account_activity_client, "get_subscriptions") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -65,16 +63,12 @@ def test_get_account_activity_subscriptions_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail( - f"Contract test failed for get_account_activity_subscriptions: {e}" - ) + pytest.fail(f"Contract test failed for get_subscriptions: {e}") - def test_get_account_activity_subscriptions_required_parameters(self): - """Test that get_account_activity_subscriptions handles parameters correctly.""" - method = getattr( - self.account_activity_client, "get_account_activity_subscriptions" - ) + def test_get_subscriptions_required_parameters(self): + """Test that get_subscriptions handles parameters correctly.""" + method = getattr(self.account_activity_client, "get_subscriptions") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -88,8 +82,8 @@ def test_get_account_activity_subscriptions_required_parameters(self): method() - def test_get_account_activity_subscriptions_response_structure(self): - """Test get_account_activity_subscriptions response structure validation.""" + def test_get_subscriptions_response_structure(self): + """Test get_subscriptions response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -105,9 +99,7 @@ def test_get_account_activity_subscriptions_response_structure(self): kwargs["webhook_id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr( - self.account_activity_client, "get_account_activity_subscriptions" - ) + method = getattr(self.account_activity_client, "get_subscriptions") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -119,8 +111,8 @@ def test_get_account_activity_subscriptions_response_structure(self): ) - def test_validate_account_activity_subscription_request_structure(self): - """Test validate_account_activity_subscription request structure.""" + def test_validate_subscription_request_structure(self): + """Test validate_subscription request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -137,10 +129,7 @@ def test_validate_account_activity_subscription_request_structure(self): # Add request body if required # Call the method try: - method = getattr( - self.account_activity_client, - "validate_account_activity_subscription", - ) + method = getattr(self.account_activity_client, "validate_subscription") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -161,16 +150,12 @@ def test_validate_account_activity_subscription_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail( - f"Contract test failed for validate_account_activity_subscription: {e}" - ) + pytest.fail(f"Contract test failed for validate_subscription: {e}") - def test_validate_account_activity_subscription_required_parameters(self): - """Test that validate_account_activity_subscription handles parameters correctly.""" - method = getattr( - self.account_activity_client, "validate_account_activity_subscription" - ) + def test_validate_subscription_required_parameters(self): + """Test that validate_subscription handles parameters correctly.""" + method = getattr(self.account_activity_client, "validate_subscription") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -184,8 +169,8 @@ def test_validate_account_activity_subscription_required_parameters(self): method() - def test_validate_account_activity_subscription_response_structure(self): - """Test validate_account_activity_subscription response structure validation.""" + def test_validate_subscription_response_structure(self): + """Test validate_subscription response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -201,9 +186,7 @@ def test_validate_account_activity_subscription_response_structure(self): kwargs["webhook_id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr( - self.account_activity_client, "validate_account_activity_subscription" - ) + method = getattr(self.account_activity_client, "validate_subscription") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -215,8 +198,8 @@ def test_validate_account_activity_subscription_response_structure(self): ) - def test_get_account_activity_subscription_count_request_structure(self): - """Test get_account_activity_subscription_count request structure.""" + def test_delete_subscription_request_structure(self): + """Test delete_subscription request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -225,27 +208,26 @@ def test_get_account_activity_subscription_count_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters + kwargs["webhook_id"] = "test_value" + kwargs["user_id"] = "test_value" # Add request body if required # Call the method try: - method = getattr( - self.account_activity_client, - "get_account_activity_subscription_count", - ) + method = getattr(self.account_activity_client, "delete_subscription") result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.delete.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.delete.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/account_activity/subscriptions/count" + expected_path = "/2/account_activity/webhooks/{webhook_id}/subscriptions/{user_id}/all" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -254,31 +236,27 @@ def test_get_account_activity_subscription_count_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail( - f"Contract test failed for get_account_activity_subscription_count: {e}" - ) + pytest.fail(f"Contract test failed for delete_subscription: {e}") - def test_get_account_activity_subscription_count_required_parameters(self): - """Test that get_account_activity_subscription_count handles parameters correctly.""" - method = getattr( - self.account_activity_client, "get_account_activity_subscription_count" - ) - # No required parameters, method should be callable without args + def test_delete_subscription_required_parameters(self): + """Test that delete_subscription handles parameters correctly.""" + method = getattr(self.account_activity_client, "delete_subscription") + # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: + # Mock a 400 response (typical for missing required parameters) mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: + mock_response.status_code = 400 + mock_response.json.return_value = {"error": "Missing required parameters"} + mock_response.raise_for_status.side_effect = Exception("Bad Request") + mock_session.delete.return_value = mock_response + # Call without required parameters should either raise locally or via server response + with pytest.raises((TypeError, ValueError, Exception)): method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - def test_get_account_activity_subscription_count_response_structure(self): - """Test get_account_activity_subscription_count response structure validation.""" + def test_delete_subscription_response_structure(self): + """Test delete_subscription response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -288,14 +266,14 @@ def test_get_account_activity_subscription_count_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare minimal valid parameters kwargs = {} + kwargs["webhook_id"] = "test" + kwargs["user_id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr( - self.account_activity_client, "get_account_activity_subscription_count" - ) + method = getattr(self.account_activity_client, "delete_subscription") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -307,8 +285,8 @@ def test_get_account_activity_subscription_count_response_structure(self): ) - def test_delete_account_activity_subscription_request_structure(self): - """Test delete_account_activity_subscription request structure.""" + def test_get_subscription_count_request_structure(self): + """Test get_subscription_count request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -317,28 +295,24 @@ def test_delete_account_activity_subscription_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["webhook_id"] = "test_value" - kwargs["user_id"] = "test_value" # Add request body if required # Call the method try: - method = getattr( - self.account_activity_client, "delete_account_activity_subscription" - ) + method = getattr(self.account_activity_client, "get_subscription_count") result = method(**kwargs) # Verify the request was made - mock_session.delete.assert_called_once() + mock_session.get.assert_called_once() # Verify request structure - call_args = mock_session.delete.call_args + call_args = mock_session.get.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/account_activity/webhooks/{webhook_id}/subscriptions/{user_id}/all" + expected_path = "/2/account_activity/subscriptions/count" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -347,31 +321,27 @@ def test_delete_account_activity_subscription_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail( - f"Contract test failed for delete_account_activity_subscription: {e}" - ) + pytest.fail(f"Contract test failed for get_subscription_count: {e}") - def test_delete_account_activity_subscription_required_parameters(self): - """Test that delete_account_activity_subscription handles parameters correctly.""" - method = getattr( - self.account_activity_client, "delete_account_activity_subscription" - ) - # Test with missing required parameters - mock the request to avoid network calls + def test_get_subscription_count_required_parameters(self): + """Test that get_subscription_count handles parameters correctly.""" + method = getattr(self.account_activity_client, "get_subscription_count") + # No required parameters, method should be callable without args with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): + mock_response.status_code = 200 + mock_response.json.return_value = {} + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + try: method() + except Exception as e: + pytest.fail(f"Method with no required params should be callable: {e}") - def test_delete_account_activity_subscription_response_structure(self): - """Test delete_account_activity_subscription response structure validation.""" + def test_get_subscription_count_response_structure(self): + """Test get_subscription_count response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -381,16 +351,12 @@ def test_delete_account_activity_subscription_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["webhook_id"] = "test" - kwargs["user_id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr( - self.account_activity_client, "delete_account_activity_subscription" - ) + method = getattr(self.account_activity_client, "get_subscription_count") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -402,8 +368,8 @@ def test_delete_account_activity_subscription_response_structure(self): ) - def test_create_account_activity_replay_job_request_structure(self): - """Test create_account_activity_replay_job request structure.""" + def test_create_replay_job_request_structure(self): + """Test create_replay_job request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -422,9 +388,7 @@ def test_create_account_activity_replay_job_request_structure(self): # Add request body if required # Call the method try: - method = getattr( - self.account_activity_client, "create_account_activity_replay_job" - ) + method = getattr(self.account_activity_client, "create_replay_job") result = method(**kwargs) # Verify the request was made mock_session.post.assert_called_once() @@ -445,16 +409,12 @@ def test_create_account_activity_replay_job_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail( - f"Contract test failed for create_account_activity_replay_job: {e}" - ) + pytest.fail(f"Contract test failed for create_replay_job: {e}") - def test_create_account_activity_replay_job_required_parameters(self): - """Test that create_account_activity_replay_job handles parameters correctly.""" - method = getattr( - self.account_activity_client, "create_account_activity_replay_job" - ) + def test_create_replay_job_required_parameters(self): + """Test that create_replay_job handles parameters correctly.""" + method = getattr(self.account_activity_client, "create_replay_job") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -468,8 +428,8 @@ def test_create_account_activity_replay_job_required_parameters(self): method() - def test_create_account_activity_replay_job_response_structure(self): - """Test create_account_activity_replay_job response structure validation.""" + def test_create_replay_job_response_structure(self): + """Test create_replay_job response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -487,9 +447,7 @@ def test_create_account_activity_replay_job_response_structure(self): kwargs["to_date"] = "test_value" # Add request body if required # Call method and verify response structure - method = getattr( - self.account_activity_client, "create_account_activity_replay_job" - ) + method = getattr(self.account_activity_client, "create_replay_job") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed diff --git a/xdk/python/tests/account_activity/test_generic.py b/xdk/python/tests/account_activity/test_generic.py index 9fa5411d..93a0424d 100644 --- a/xdk/python/tests/account_activity/test_generic.py +++ b/xdk/python/tests/account_activity/test_generic.py @@ -1,5 +1,5 @@ """ -Auto-generated generic tests for Account_Activity client. +Auto-generated generic tests for {"class_name": "AccountActivity", "display_name": "account activity", "import_name": "account_activity", "original": ["account", "activity"], "property_name": "account_activity"} client. This module contains general tests that validate the overall client functionality, imports, and error handling that don't need to be diff --git a/xdk/python/tests/account_activity/test_structure.py b/xdk/python/tests/account_activity/test_structure.py index 7399c07f..16688f32 100644 --- a/xdk/python/tests/account_activity/test_structure.py +++ b/xdk/python/tests/account_activity/test_structure.py @@ -1,8 +1,8 @@ """ -Auto-generated structural tests for Account_Activity client. +Auto-generated structural tests for {"class_name": "AccountActivity", "display_name": "account activity", "import_name": "account_activity", "original": ["account", "activity"], "property_name": "account_activity"} client. This module contains tests that validate the structure and API surface -of the Account_Activity client. These tests ensure that all expected methods +of the {"class_name": "AccountActivity", "display_name": "account activity", "import_name": "account_activity", "original": ["account", "activity"], "property_name": "account_activity"} client. These tests ensure that all expected methods exist and have the correct signatures. Generated automatically - do not edit manually. @@ -25,24 +25,22 @@ def setup_class(self): self.account_activity_client = getattr(self.client, "account_activity") - def test_get_account_activity_subscriptions_exists(self): - """Test that get_account_activity_subscriptions method exists with correct signature.""" + def test_get_subscriptions_exists(self): + """Test that get_subscriptions method exists with correct signature.""" # Check method exists - method = getattr( - AccountActivityClient, "get_account_activity_subscriptions", None - ) + method = getattr(AccountActivityClient, "get_subscriptions", None) assert ( method is not None - ), f"Method get_account_activity_subscriptions does not exist on AccountActivityClient" + ), f"Method get_subscriptions does not exist on AccountActivityClient" # Check method is callable - assert callable(method), f"get_account_activity_subscriptions is not callable" + assert callable(method), f"get_subscriptions is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"get_account_activity_subscriptions should have at least 'self' parameter" + ), f"get_subscriptions should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -53,7 +51,7 @@ def test_get_account_activity_subscriptions_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_account_activity_subscriptions" + ), f"Required parameter '{required_param}' missing from get_subscriptions" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -64,36 +62,32 @@ def test_get_account_activity_subscriptions_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_account_activity_subscriptions_return_annotation(self): - """Test that get_account_activity_subscriptions has proper return type annotation.""" - method = getattr(AccountActivityClient, "get_account_activity_subscriptions") + def test_get_subscriptions_return_annotation(self): + """Test that get_subscriptions has proper return type annotation.""" + method = getattr(AccountActivityClient, "get_subscriptions") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_account_activity_subscriptions should have return type annotation" + ), f"Method get_subscriptions should have return type annotation" - def test_validate_account_activity_subscription_exists(self): - """Test that validate_account_activity_subscription method exists with correct signature.""" + def test_validate_subscription_exists(self): + """Test that validate_subscription method exists with correct signature.""" # Check method exists - method = getattr( - AccountActivityClient, "validate_account_activity_subscription", None - ) + method = getattr(AccountActivityClient, "validate_subscription", None) assert ( method is not None - ), f"Method validate_account_activity_subscription does not exist on AccountActivityClient" + ), f"Method validate_subscription does not exist on AccountActivityClient" # Check method is callable - assert callable( - method - ), f"validate_account_activity_subscription is not callable" + assert callable(method), f"validate_subscription is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"validate_account_activity_subscription should have at least 'self' parameter" + ), f"validate_subscription should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -104,7 +98,7 @@ def test_validate_account_activity_subscription_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from validate_account_activity_subscription" + ), f"Required parameter '{required_param}' missing from validate_subscription" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -115,47 +109,44 @@ def test_validate_account_activity_subscription_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_validate_account_activity_subscription_return_annotation(self): - """Test that validate_account_activity_subscription has proper return type annotation.""" - method = getattr( - AccountActivityClient, "validate_account_activity_subscription" - ) + def test_validate_subscription_return_annotation(self): + """Test that validate_subscription has proper return type annotation.""" + method = getattr(AccountActivityClient, "validate_subscription") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method validate_account_activity_subscription should have return type annotation" + ), f"Method validate_subscription should have return type annotation" - def test_get_account_activity_subscription_count_exists(self): - """Test that get_account_activity_subscription_count method exists with correct signature.""" + def test_delete_subscription_exists(self): + """Test that delete_subscription method exists with correct signature.""" # Check method exists - method = getattr( - AccountActivityClient, "get_account_activity_subscription_count", None - ) + method = getattr(AccountActivityClient, "delete_subscription", None) assert ( method is not None - ), f"Method get_account_activity_subscription_count does not exist on AccountActivityClient" + ), f"Method delete_subscription does not exist on AccountActivityClient" # Check method is callable - assert callable( - method - ), f"get_account_activity_subscription_count is not callable" + assert callable(method), f"delete_subscription is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"get_account_activity_subscription_count should have at least 'self' parameter" + ), f"delete_subscription should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [] + required_params = [ + "webhook_id", + "user_id", + ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_account_activity_subscription_count" + ), f"Required parameter '{required_param}' missing from delete_subscription" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -166,48 +157,41 @@ def test_get_account_activity_subscription_count_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_account_activity_subscription_count_return_annotation(self): - """Test that get_account_activity_subscription_count has proper return type annotation.""" - method = getattr( - AccountActivityClient, "get_account_activity_subscription_count" - ) + def test_delete_subscription_return_annotation(self): + """Test that delete_subscription has proper return type annotation.""" + method = getattr(AccountActivityClient, "delete_subscription") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_account_activity_subscription_count should have return type annotation" + ), f"Method delete_subscription should have return type annotation" - def test_delete_account_activity_subscription_exists(self): - """Test that delete_account_activity_subscription method exists with correct signature.""" + def test_get_subscription_count_exists(self): + """Test that get_subscription_count method exists with correct signature.""" # Check method exists - method = getattr( - AccountActivityClient, "delete_account_activity_subscription", None - ) + method = getattr(AccountActivityClient, "get_subscription_count", None) assert ( method is not None - ), f"Method delete_account_activity_subscription does not exist on AccountActivityClient" + ), f"Method get_subscription_count does not exist on AccountActivityClient" # Check method is callable - assert callable(method), f"delete_account_activity_subscription is not callable" + assert callable(method), f"get_subscription_count is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"delete_account_activity_subscription should have at least 'self' parameter" + ), f"get_subscription_count should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [ - "webhook_id", - "user_id", - ] + required_params = [] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from delete_account_activity_subscription" + ), f"Required parameter '{required_param}' missing from get_subscription_count" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -218,34 +202,32 @@ def test_delete_account_activity_subscription_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_delete_account_activity_subscription_return_annotation(self): - """Test that delete_account_activity_subscription has proper return type annotation.""" - method = getattr(AccountActivityClient, "delete_account_activity_subscription") + def test_get_subscription_count_return_annotation(self): + """Test that get_subscription_count has proper return type annotation.""" + method = getattr(AccountActivityClient, "get_subscription_count") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method delete_account_activity_subscription should have return type annotation" + ), f"Method get_subscription_count should have return type annotation" - def test_create_account_activity_replay_job_exists(self): - """Test that create_account_activity_replay_job method exists with correct signature.""" + def test_create_replay_job_exists(self): + """Test that create_replay_job method exists with correct signature.""" # Check method exists - method = getattr( - AccountActivityClient, "create_account_activity_replay_job", None - ) + method = getattr(AccountActivityClient, "create_replay_job", None) assert ( method is not None - ), f"Method create_account_activity_replay_job does not exist on AccountActivityClient" + ), f"Method create_replay_job does not exist on AccountActivityClient" # Check method is callable - assert callable(method), f"create_account_activity_replay_job is not callable" + assert callable(method), f"create_replay_job is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"create_account_activity_replay_job should have at least 'self' parameter" + ), f"create_replay_job should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -258,7 +240,7 @@ def test_create_account_activity_replay_job_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from create_account_activity_replay_job" + ), f"Required parameter '{required_param}' missing from create_replay_job" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -269,24 +251,24 @@ def test_create_account_activity_replay_job_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_create_account_activity_replay_job_return_annotation(self): - """Test that create_account_activity_replay_job has proper return type annotation.""" - method = getattr(AccountActivityClient, "create_account_activity_replay_job") + def test_create_replay_job_return_annotation(self): + """Test that create_replay_job has proper return type annotation.""" + method = getattr(AccountActivityClient, "create_replay_job") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method create_account_activity_replay_job should have return type annotation" + ), f"Method create_replay_job should have return type annotation" def test_all_expected_methods_exist(self): """Test that all expected methods exist on the client.""" expected_methods = [ - "get_account_activity_subscriptions", - "validate_account_activity_subscription", - "get_account_activity_subscription_count", - "delete_account_activity_subscription", - "create_account_activity_replay_job", + "get_subscriptions", + "validate_subscription", + "delete_subscription", + "get_subscription_count", + "create_replay_job", ] for expected_method in expected_methods: assert hasattr( diff --git a/xdk/python/tests/bookmarks/test_contracts.py b/xdk/python/tests/bookmarks/test_contracts.py index 21e5ef19..60a66b66 100644 --- a/xdk/python/tests/bookmarks/test_contracts.py +++ b/xdk/python/tests/bookmarks/test_contracts.py @@ -1,8 +1,8 @@ """ -Auto-generated contract tests for Bookmarks client. +Auto-generated contract tests for {"class_name": "Bookmarks", "display_name": "bookmarks", "import_name": "bookmarks", "original": ["bookmarks"], "property_name": "bookmarks"} client. This module contains tests that validate the request/response contracts -of the Bookmarks client against the OpenAPI specification. +of the {"class_name": "Bookmarks", "display_name": "bookmarks", "import_name": "bookmarks", "original": ["bookmarks"], "property_name": "bookmarks"} client against the OpenAPI specification. Generated automatically - do not edit manually. """ @@ -24,8 +24,8 @@ def setup_class(self): self.bookmarks_client = getattr(self.client, "bookmarks") - def test_get_users_bookmarks_by_folder_id_request_structure(self): - """Test get_users_bookmarks_by_folder_id request structure.""" + def test_get_users_bookmark_folders_request_structure(self): + """Test get_users_bookmark_folders request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -39,13 +39,10 @@ def test_get_users_bookmarks_by_folder_id_request_structure(self): kwargs = {} # Add required parameters kwargs["id"] = "test_value" - kwargs["folder_id"] = "test_value" # Add request body if required # Call the method try: - method = getattr( - self.bookmarks_client, "get_users_bookmarks_by_folder_id" - ) + method = getattr(self.bookmarks_client, "get_users_bookmark_folders") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -55,7 +52,7 @@ def test_get_users_bookmarks_by_folder_id_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/bookmarks/folders/{folder_id}" + expected_path = "/2/users/{id}/bookmarks/folders" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -64,14 +61,12 @@ def test_get_users_bookmarks_by_folder_id_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail( - f"Contract test failed for get_users_bookmarks_by_folder_id: {e}" - ) + pytest.fail(f"Contract test failed for get_users_bookmark_folders: {e}") - def test_get_users_bookmarks_by_folder_id_required_parameters(self): - """Test that get_users_bookmarks_by_folder_id handles parameters correctly.""" - method = getattr(self.bookmarks_client, "get_users_bookmarks_by_folder_id") + def test_get_users_bookmark_folders_required_parameters(self): + """Test that get_users_bookmark_folders handles parameters correctly.""" + method = getattr(self.bookmarks_client, "get_users_bookmark_folders") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -85,8 +80,8 @@ def test_get_users_bookmarks_by_folder_id_required_parameters(self): method() - def test_get_users_bookmarks_by_folder_id_response_structure(self): - """Test get_users_bookmarks_by_folder_id response structure validation.""" + def test_get_users_bookmark_folders_response_structure(self): + """Test get_users_bookmark_folders response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -100,10 +95,9 @@ def test_get_users_bookmarks_by_folder_id_response_structure(self): # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" - kwargs["folder_id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.bookmarks_client, "get_users_bookmarks_by_folder_id") + method = getattr(self.bookmarks_client, "get_users_bookmark_folders") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -115,8 +109,8 @@ def test_get_users_bookmarks_by_folder_id_response_structure(self): ) - def test_get_users_bookmarks_request_structure(self): - """Test get_users_bookmarks request structure.""" + def test_get_users_by_folder_id_request_structure(self): + """Test get_users_by_folder_id request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -130,10 +124,11 @@ def test_get_users_bookmarks_request_structure(self): kwargs = {} # Add required parameters kwargs["id"] = "test_value" + kwargs["folder_id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.bookmarks_client, "get_users_bookmarks") + method = getattr(self.bookmarks_client, "get_users_by_folder_id") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -143,7 +138,7 @@ def test_get_users_bookmarks_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/bookmarks" + expected_path = "/2/users/{id}/bookmarks/folders/{folder_id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -152,12 +147,12 @@ def test_get_users_bookmarks_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_bookmarks: {e}") + pytest.fail(f"Contract test failed for get_users_by_folder_id: {e}") - def test_get_users_bookmarks_required_parameters(self): - """Test that get_users_bookmarks handles parameters correctly.""" - method = getattr(self.bookmarks_client, "get_users_bookmarks") + def test_get_users_by_folder_id_required_parameters(self): + """Test that get_users_by_folder_id handles parameters correctly.""" + method = getattr(self.bookmarks_client, "get_users_by_folder_id") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -171,8 +166,8 @@ def test_get_users_bookmarks_required_parameters(self): method() - def test_get_users_bookmarks_response_structure(self): - """Test get_users_bookmarks response structure validation.""" + def test_get_users_by_folder_id_response_structure(self): + """Test get_users_by_folder_id response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -186,9 +181,10 @@ def test_get_users_bookmarks_response_structure(self): # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" + kwargs["folder_id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.bookmarks_client, "get_users_bookmarks") + method = getattr(self.bookmarks_client, "get_users_by_folder_id") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -378,88 +374,3 @@ def test_delete_users_bookmark_response_structure(self): pytest.fail( f"Accessing optional field 'data' should not cause errors: {e}" ) - - - def test_get_users_bookmark_folders_request_structure(self): - """Test get_users_bookmark_folders request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.bookmarks_client, "get_users_bookmark_folders") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/bookmarks/folders" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_users_bookmark_folders: {e}") - - - def test_get_users_bookmark_folders_required_parameters(self): - """Test that get_users_bookmark_folders handles parameters correctly.""" - method = getattr(self.bookmarks_client, "get_users_bookmark_folders") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_users_bookmark_folders_response_structure(self): - """Test get_users_bookmark_folders response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.bookmarks_client, "get_users_bookmark_folders") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/tests/bookmarks/test_generic.py b/xdk/python/tests/bookmarks/test_generic.py index 35d5d808..d2f1659a 100644 --- a/xdk/python/tests/bookmarks/test_generic.py +++ b/xdk/python/tests/bookmarks/test_generic.py @@ -1,5 +1,5 @@ """ -Auto-generated generic tests for Bookmarks client. +Auto-generated generic tests for {"class_name": "Bookmarks", "display_name": "bookmarks", "import_name": "bookmarks", "original": ["bookmarks"], "property_name": "bookmarks"} client. This module contains general tests that validate the overall client functionality, imports, and error handling that don't need to be diff --git a/xdk/python/tests/bookmarks/test_pagination.py b/xdk/python/tests/bookmarks/test_pagination.py index 3d1df9fb..3bd9fbff 100644 --- a/xdk/python/tests/bookmarks/test_pagination.py +++ b/xdk/python/tests/bookmarks/test_pagination.py @@ -1,5 +1,5 @@ """ -Auto-generated pagination tests for Bookmarks client. +Auto-generated pagination tests for {"class_name": "Bookmarks", "display_name": "bookmarks", "import_name": "bookmarks", "original": ["bookmarks"], "property_name": "bookmarks"} client. This module contains tests that validate pagination functionality using the Cursor class for methods that support pagination. @@ -23,148 +23,6 @@ def setup_class(self): self.bookmarks_client = getattr(self.client, "bookmarks") - def test_get_users_bookmarks_cursor_creation(self): - """Test that get_users_bookmarks can be used with Cursor.""" - method = getattr(self.bookmarks_client, "get_users_bookmarks") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersBookmarks should support pagination") - - - def test_get_users_bookmarks_cursor_pages(self): - """Test pagination with pages() for get_users_bookmarks.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.bookmarks_client, "get_users_bookmarks") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_bookmarks_cursor_items(self): - """Test pagination with items() for get_users_bookmarks.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.bookmarks_client, "get_users_bookmarks") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_bookmarks_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_bookmarks.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.bookmarks_client, "get_users_bookmarks") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [], - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - def test_get_users_bookmark_folders_cursor_creation(self): """Test that get_users_bookmark_folders can be used with Cursor.""" method = getattr(self.bookmarks_client, "get_users_bookmark_folders") @@ -174,7 +32,7 @@ def test_get_users_bookmark_folders_cursor_creation(self): assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method getUsersBookmarkFolders should support pagination") + pytest.fail(f"Method get_users_bookmark_folders should support pagination") def test_get_users_bookmark_folders_cursor_pages(self): @@ -317,7 +175,7 @@ def test_pagination_edge_cases(self): empty_response.raise_for_status.return_value = None mock_session.get.return_value = empty_response # Pick first paginatable method for testing - method = getattr(self.bookmarks_client, "get_users_bookmarks") + method = getattr(self.bookmarks_client, "get_users_bookmark_folders") test_cursor = cursor(method, "test_id", max_results=10) # Should handle empty responses gracefully pages = list(test_cursor.pages(1)) diff --git a/xdk/python/tests/bookmarks/test_structure.py b/xdk/python/tests/bookmarks/test_structure.py index 357ded57..2b8cd776 100644 --- a/xdk/python/tests/bookmarks/test_structure.py +++ b/xdk/python/tests/bookmarks/test_structure.py @@ -1,8 +1,8 @@ """ -Auto-generated structural tests for Bookmarks client. +Auto-generated structural tests for {"class_name": "Bookmarks", "display_name": "bookmarks", "import_name": "bookmarks", "original": ["bookmarks"], "property_name": "bookmarks"} client. This module contains tests that validate the structure and API surface -of the Bookmarks client. These tests ensure that all expected methods +of the {"class_name": "Bookmarks", "display_name": "bookmarks", "import_name": "bookmarks", "original": ["bookmarks"], "property_name": "bookmarks"} client. These tests ensure that all expected methods exist and have the correct signatures. Generated automatically - do not edit manually. @@ -25,36 +25,38 @@ def setup_class(self): self.bookmarks_client = getattr(self.client, "bookmarks") - def test_get_users_bookmarks_by_folder_id_exists(self): - """Test that get_users_bookmarks_by_folder_id method exists with correct signature.""" + def test_get_users_bookmark_folders_exists(self): + """Test that get_users_bookmark_folders method exists with correct signature.""" # Check method exists - method = getattr(BookmarksClient, "get_users_bookmarks_by_folder_id", None) + method = getattr(BookmarksClient, "get_users_bookmark_folders", None) assert ( method is not None - ), f"Method get_users_bookmarks_by_folder_id does not exist on BookmarksClient" + ), f"Method get_users_bookmark_folders does not exist on BookmarksClient" # Check method is callable - assert callable(method), f"get_users_bookmarks_by_folder_id is not callable" + assert callable(method), f"get_users_bookmark_folders is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"get_users_bookmarks_by_folder_id should have at least 'self' parameter" + ), f"get_users_bookmark_folders should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ "id", - "folder_id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_bookmarks_by_folder_id" + ), f"Required parameter '{required_param}' missing from get_users_bookmark_folders" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "max_results", + "pagination_token", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -63,48 +65,65 @@ def test_get_users_bookmarks_by_folder_id_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_bookmarks_by_folder_id_return_annotation(self): - """Test that get_users_bookmarks_by_folder_id has proper return type annotation.""" - method = getattr(BookmarksClient, "get_users_bookmarks_by_folder_id") + def test_get_users_bookmark_folders_return_annotation(self): + """Test that get_users_bookmark_folders has proper return type annotation.""" + method = getattr(BookmarksClient, "get_users_bookmark_folders") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_bookmarks_by_folder_id should have return type annotation" + ), f"Method get_users_bookmark_folders should have return type annotation" + + + def test_get_users_bookmark_folders_pagination_params(self): + """Test that get_users_bookmark_folders has pagination parameters.""" + method = getattr(BookmarksClient, "get_users_bookmark_folders") + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have pagination-related parameters + pagination_params = [ + "pagination_token", + "max_results", + "next_token", + "cursor", + "limit", + ] + has_pagination_param = any(param in params for param in pagination_params) + assert ( + has_pagination_param + ), f"Paginated method get_users_bookmark_folders should have pagination parameters" - def test_get_users_bookmarks_exists(self): - """Test that get_users_bookmarks method exists with correct signature.""" + def test_get_users_by_folder_id_exists(self): + """Test that get_users_by_folder_id method exists with correct signature.""" # Check method exists - method = getattr(BookmarksClient, "get_users_bookmarks", None) + method = getattr(BookmarksClient, "get_users_by_folder_id", None) assert ( method is not None - ), f"Method get_users_bookmarks does not exist on BookmarksClient" + ), f"Method get_users_by_folder_id does not exist on BookmarksClient" # Check method is callable - assert callable(method), f"get_users_bookmarks is not callable" + assert callable(method), f"get_users_by_folder_id is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"get_users_bookmarks should have at least 'self' parameter" + ), f"get_users_by_folder_id should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ "id", + "folder_id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_bookmarks" + ), f"Required parameter '{required_param}' missing from get_users_by_folder_id" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -113,33 +132,14 @@ def test_get_users_bookmarks_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_bookmarks_return_annotation(self): - """Test that get_users_bookmarks has proper return type annotation.""" - method = getattr(BookmarksClient, "get_users_bookmarks") + def test_get_users_by_folder_id_return_annotation(self): + """Test that get_users_by_folder_id has proper return type annotation.""" + method = getattr(BookmarksClient, "get_users_by_folder_id") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_bookmarks should have return type annotation" - - - def test_get_users_bookmarks_pagination_params(self): - """Test that get_users_bookmarks has pagination parameters.""" - method = getattr(BookmarksClient, "get_users_bookmarks") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_bookmarks should have pagination parameters" + ), f"Method get_users_by_folder_id should have return type annotation" def test_create_users_bookmark_exists(self): @@ -237,83 +237,13 @@ def test_delete_users_bookmark_return_annotation(self): ), f"Method delete_users_bookmark should have return type annotation" - def test_get_users_bookmark_folders_exists(self): - """Test that get_users_bookmark_folders method exists with correct signature.""" - # Check method exists - method = getattr(BookmarksClient, "get_users_bookmark_folders", None) - assert ( - method is not None - ), f"Method get_users_bookmark_folders does not exist on BookmarksClient" - # Check method is callable - assert callable(method), f"get_users_bookmark_folders is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_bookmark_folders should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_users_bookmark_folders" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_users_bookmark_folders_return_annotation(self): - """Test that get_users_bookmark_folders has proper return type annotation.""" - method = getattr(BookmarksClient, "get_users_bookmark_folders") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_bookmark_folders should have return type annotation" - - - def test_get_users_bookmark_folders_pagination_params(self): - """Test that get_users_bookmark_folders has pagination parameters.""" - method = getattr(BookmarksClient, "get_users_bookmark_folders") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_bookmark_folders should have pagination parameters" - - def test_all_expected_methods_exist(self): """Test that all expected methods exist on the client.""" expected_methods = [ - "get_users_bookmarks_by_folder_id", - "get_users_bookmarks", + "get_users_bookmark_folders", + "get_users_by_folder_id", "create_users_bookmark", "delete_users_bookmark", - "get_users_bookmark_folders", ] for expected_method in expected_methods: assert hasattr( diff --git a/xdk/python/tests/communities/test_contracts.py b/xdk/python/tests/communities/test_contracts.py index 2499c12f..465f2328 100644 --- a/xdk/python/tests/communities/test_contracts.py +++ b/xdk/python/tests/communities/test_contracts.py @@ -1,8 +1,8 @@ """ -Auto-generated contract tests for Communities client. +Auto-generated contract tests for {"class_name": "Communities", "display_name": "communities", "import_name": "communities", "original": ["communities"], "property_name": "communities"} client. This module contains tests that validate the request/response contracts -of the Communities client against the OpenAPI specification. +of the {"class_name": "Communities", "display_name": "communities", "import_name": "communities", "original": ["communities"], "property_name": "communities"} client against the OpenAPI specification. Generated automatically - do not edit manually. """ @@ -24,8 +24,8 @@ def setup_class(self): self.communities_client = getattr(self.client, "communities") - def test_search_communities_request_structure(self): - """Test search_communities request structure.""" + def test_get_by_id_request_structure(self): + """Test get_by_id request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -38,11 +38,11 @@ def test_search_communities_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["query"] = "test_query" + kwargs["id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.communities_client, "search_communities") + method = getattr(self.communities_client, "get_by_id") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -52,7 +52,7 @@ def test_search_communities_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/communities/search" + expected_path = "/2/communities/{id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -61,12 +61,12 @@ def test_search_communities_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for search_communities: {e}") + pytest.fail(f"Contract test failed for get_by_id: {e}") - def test_search_communities_required_parameters(self): - """Test that search_communities handles parameters correctly.""" - method = getattr(self.communities_client, "search_communities") + def test_get_by_id_required_parameters(self): + """Test that get_by_id handles parameters correctly.""" + method = getattr(self.communities_client, "get_by_id") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -80,8 +80,8 @@ def test_search_communities_required_parameters(self): method() - def test_search_communities_response_structure(self): - """Test search_communities response structure validation.""" + def test_get_by_id_response_structure(self): + """Test get_by_id response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -94,10 +94,10 @@ def test_search_communities_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["query"] = "test_value" + kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.communities_client, "search_communities") + method = getattr(self.communities_client, "get_by_id") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -109,8 +109,8 @@ def test_search_communities_response_structure(self): ) - def test_get_communities_by_id_request_structure(self): - """Test get_communities_by_id request structure.""" + def test_search_request_structure(self): + """Test search request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -123,11 +123,11 @@ def test_get_communities_by_id_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["id"] = "test_value" + kwargs["query"] = "test_query" # Add request body if required # Call the method try: - method = getattr(self.communities_client, "get_communities_by_id") + method = getattr(self.communities_client, "search") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -137,7 +137,7 @@ def test_get_communities_by_id_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/communities/{id}" + expected_path = "/2/communities/search" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -146,12 +146,12 @@ def test_get_communities_by_id_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_communities_by_id: {e}") + pytest.fail(f"Contract test failed for search: {e}") - def test_get_communities_by_id_required_parameters(self): - """Test that get_communities_by_id handles parameters correctly.""" - method = getattr(self.communities_client, "get_communities_by_id") + def test_search_required_parameters(self): + """Test that search handles parameters correctly.""" + method = getattr(self.communities_client, "search") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -165,8 +165,8 @@ def test_get_communities_by_id_required_parameters(self): method() - def test_get_communities_by_id_response_structure(self): - """Test get_communities_by_id response structure validation.""" + def test_search_response_structure(self): + """Test search response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -179,10 +179,10 @@ def test_get_communities_by_id_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["id"] = "test" + kwargs["query"] = "test_value" # Add request body if required # Call method and verify response structure - method = getattr(self.communities_client, "get_communities_by_id") + method = getattr(self.communities_client, "search") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed diff --git a/xdk/python/tests/communities/test_generic.py b/xdk/python/tests/communities/test_generic.py index be58e9f8..4cbcfd41 100644 --- a/xdk/python/tests/communities/test_generic.py +++ b/xdk/python/tests/communities/test_generic.py @@ -1,5 +1,5 @@ """ -Auto-generated generic tests for Communities client. +Auto-generated generic tests for {"class_name": "Communities", "display_name": "communities", "import_name": "communities", "original": ["communities"], "property_name": "communities"} client. This module contains general tests that validate the overall client functionality, imports, and error handling that don't need to be diff --git a/xdk/python/tests/communities/test_pagination.py b/xdk/python/tests/communities/test_pagination.py index 7ef426fd..38517fd4 100644 --- a/xdk/python/tests/communities/test_pagination.py +++ b/xdk/python/tests/communities/test_pagination.py @@ -1,5 +1,5 @@ """ -Auto-generated pagination tests for Communities client. +Auto-generated pagination tests for {"class_name": "Communities", "display_name": "communities", "import_name": "communities", "original": ["communities"], "property_name": "communities"} client. This module contains tests that validate pagination functionality using the Cursor class for methods that support pagination. @@ -23,20 +23,20 @@ def setup_class(self): self.communities_client = getattr(self.client, "communities") - def test_search_communities_cursor_creation(self): - """Test that search_communities can be used with Cursor.""" - method = getattr(self.communities_client, "search_communities") + def test_search_cursor_creation(self): + """Test that search can be used with Cursor.""" + method = getattr(self.communities_client, "search") # Should be able to create cursor without error try: test_cursor = cursor(method, "test_query", max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method searchCommunities should support pagination") + pytest.fail(f"Method search should support pagination") - def test_search_communities_cursor_pages(self): - """Test pagination with pages() for search_communities.""" + def test_search_cursor_pages(self): + """Test pagination with pages() for search.""" with patch.object(self.client, "session") as mock_session: # Mock first page response first_page_response = Mock() @@ -57,7 +57,7 @@ def test_search_communities_cursor_pages(self): # Return different responses for consecutive calls mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.communities_client, "search_communities") + method = getattr(self.communities_client, "search") test_cursor = cursor(method, "test_query", max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" @@ -73,8 +73,8 @@ def test_search_communities_cursor_pages(self): assert len(second_data) == 1, "Second page should have 1 item" - def test_search_communities_cursor_items(self): - """Test pagination with items() for search_communities.""" + def test_search_cursor_items(self): + """Test pagination with items() for search.""" with patch.object(self.client, "session") as mock_session: # Mock response with paginated data mock_response = Mock() @@ -93,7 +93,7 @@ def test_search_communities_cursor_items(self): mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.communities_client, "search_communities") + method = getattr(self.communities_client, "search") test_cursor = cursor(method, "test_query", max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items assert len(items) == 3, f"Should get 3 items, got {len(items)}" @@ -104,15 +104,15 @@ def test_search_communities_cursor_items(self): ), "Items should have 'id' field" - def test_search_communities_pagination_parameters(self): - """Test that pagination parameters are handled correctly for search_communities.""" + def test_search_pagination_parameters(self): + """Test that pagination parameters are handled correctly for search.""" with patch.object(self.client, "session") as mock_session: mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.communities_client, "search_communities") + method = getattr(self.communities_client, "search") # Test with max_results parameter test_cursor = cursor(method, "test_query", max_results=5) list(test_cursor.pages(1)) # Trigger one request @@ -175,7 +175,7 @@ def test_pagination_edge_cases(self): empty_response.raise_for_status.return_value = None mock_session.get.return_value = empty_response # Pick first paginatable method for testing - method = getattr(self.communities_client, "search_communities") + method = getattr(self.communities_client, "search") test_cursor = cursor(method, "test_query", max_results=10) # Should handle empty responses gracefully pages = list(test_cursor.pages(1)) diff --git a/xdk/python/tests/communities/test_structure.py b/xdk/python/tests/communities/test_structure.py index a5300864..2254fdcf 100644 --- a/xdk/python/tests/communities/test_structure.py +++ b/xdk/python/tests/communities/test_structure.py @@ -1,8 +1,8 @@ """ -Auto-generated structural tests for Communities client. +Auto-generated structural tests for {"class_name": "Communities", "display_name": "communities", "import_name": "communities", "original": ["communities"], "property_name": "communities"} client. This module contains tests that validate the structure and API surface -of the Communities client. These tests ensure that all expected methods +of the {"class_name": "Communities", "display_name": "communities", "import_name": "communities", "original": ["communities"], "property_name": "communities"} client. These tests ensure that all expected methods exist and have the correct signatures. Generated automatically - do not edit manually. @@ -25,39 +25,33 @@ def setup_class(self): self.communities_client = getattr(self.client, "communities") - def test_search_communities_exists(self): - """Test that search_communities method exists with correct signature.""" + def test_get_by_id_exists(self): + """Test that get_by_id method exists with correct signature.""" # Check method exists - method = getattr(CommunitiesClient, "search_communities", None) + method = getattr(CommunitiesClient, "get_by_id", None) assert ( method is not None - ), f"Method search_communities does not exist on CommunitiesClient" + ), f"Method get_by_id does not exist on CommunitiesClient" # Check method is callable - assert callable(method), f"search_communities is not callable" + assert callable(method), f"get_by_id is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"search_communities should have at least 'self' parameter" + assert len(params) >= 1, f"get_by_id should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "query", + "id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from search_communities" + ), f"Required parameter '{required_param}' missing from get_by_id" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "next_token", - "pagination_token", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -66,64 +60,45 @@ def test_search_communities_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_search_communities_return_annotation(self): - """Test that search_communities has proper return type annotation.""" - method = getattr(CommunitiesClient, "search_communities") + def test_get_by_id_return_annotation(self): + """Test that get_by_id has proper return type annotation.""" + method = getattr(CommunitiesClient, "get_by_id") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method search_communities should have return type annotation" + ), f"Method get_by_id should have return type annotation" - def test_search_communities_pagination_params(self): - """Test that search_communities has pagination parameters.""" - method = getattr(CommunitiesClient, "search_communities") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method search_communities should have pagination parameters" - - - def test_get_communities_by_id_exists(self): - """Test that get_communities_by_id method exists with correct signature.""" + def test_search_exists(self): + """Test that search method exists with correct signature.""" # Check method exists - method = getattr(CommunitiesClient, "get_communities_by_id", None) - assert ( - method is not None - ), f"Method get_communities_by_id does not exist on CommunitiesClient" + method = getattr(CommunitiesClient, "search", None) + assert method is not None, f"Method search does not exist on CommunitiesClient" # Check method is callable - assert callable(method), f"get_communities_by_id is not callable" + assert callable(method), f"search is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_communities_by_id should have at least 'self' parameter" + assert len(params) >= 1, f"search should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "id", + "query", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_communities_by_id" + ), f"Required parameter '{required_param}' missing from search" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "max_results", + "next_token", + "pagination_token", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -132,21 +107,40 @@ def test_get_communities_by_id_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_communities_by_id_return_annotation(self): - """Test that get_communities_by_id has proper return type annotation.""" - method = getattr(CommunitiesClient, "get_communities_by_id") + def test_search_return_annotation(self): + """Test that search has proper return type annotation.""" + method = getattr(CommunitiesClient, "search") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_communities_by_id should have return type annotation" + ), f"Method search should have return type annotation" + + + def test_search_pagination_params(self): + """Test that search has pagination parameters.""" + method = getattr(CommunitiesClient, "search") + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have pagination-related parameters + pagination_params = [ + "pagination_token", + "max_results", + "next_token", + "cursor", + "limit", + ] + has_pagination_param = any(param in params for param in pagination_params) + assert ( + has_pagination_param + ), f"Paginated method search should have pagination parameters" def test_all_expected_methods_exist(self): """Test that all expected methods exist on the client.""" expected_methods = [ - "search_communities", - "get_communities_by_id", + "get_by_id", + "search", ] for expected_method in expected_methods: assert hasattr( diff --git a/xdk/python/tests/community_notes/test_contracts.py b/xdk/python/tests/community_notes/test_contracts.py index 6cecc0ee..3dc49f3e 100644 --- a/xdk/python/tests/community_notes/test_contracts.py +++ b/xdk/python/tests/community_notes/test_contracts.py @@ -1,8 +1,8 @@ """ -Auto-generated contract tests for Community_Notes client. +Auto-generated contract tests for {"class_name": "CommunityNotes", "display_name": "community notes", "import_name": "community_notes", "original": ["community", "notes"], "property_name": "community_notes"} client. This module contains tests that validate the request/response contracts -of the Community_Notes client against the OpenAPI specification. +of the {"class_name": "CommunityNotes", "display_name": "community notes", "import_name": "community_notes", "original": ["community", "notes"], "property_name": "community_notes"} client against the OpenAPI specification. Generated automatically - do not edit manually. """ @@ -24,8 +24,8 @@ def setup_class(self): self.community_notes_client = getattr(self.client, "community_notes") - def test_create_notes_request_structure(self): - """Test create_notes request structure.""" + def test_search_eligible_posts_request_structure(self): + """Test search_eligible_posts request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -34,28 +34,25 @@ def test_create_notes_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters + kwargs["test_mode"] = True # Add request body if required - # Import and create proper request model instance - from xdk.community_notes.models import CreateNotesRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateNotesRequest() # Call the method try: - method = getattr(self.community_notes_client, "create_notes") + method = getattr(self.community_notes_client, "search_eligible_posts") result = method(**kwargs) # Verify the request was made - mock_session.post.assert_called_once() + mock_session.get.assert_called_once() # Verify request structure - call_args = mock_session.post.call_args + call_args = mock_session.get.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/notes" + expected_path = "/2/notes/search/posts_eligible_for_notes" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -64,12 +61,12 @@ def test_create_notes_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for create_notes: {e}") + pytest.fail(f"Contract test failed for search_eligible_posts: {e}") - def test_create_notes_required_parameters(self): - """Test that create_notes handles parameters correctly.""" - method = getattr(self.community_notes_client, "create_notes") + def test_search_eligible_posts_required_parameters(self): + """Test that search_eligible_posts handles parameters correctly.""" + method = getattr(self.community_notes_client, "search_eligible_posts") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -77,14 +74,14 @@ def test_create_notes_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_create_notes_response_structure(self): - """Test create_notes response structure validation.""" + def test_search_eligible_posts_response_structure(self): + """Test search_eligible_posts response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -94,16 +91,13 @@ def test_create_notes_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} + kwargs["test_mode"] = True # Add request body if required - # Import and create proper request model instance - from xdk.community_notes.models import CreateNotesRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateNotesRequest() # Call method and verify response structure - method = getattr(self.community_notes_client, "create_notes") + method = getattr(self.community_notes_client, "search_eligible_posts") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -115,8 +109,8 @@ def test_create_notes_response_structure(self): ) - def test_delete_notes_request_structure(self): - """Test delete_notes request structure.""" + def test_create_request_structure(self): + """Test create request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -125,25 +119,28 @@ def test_delete_notes_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["id"] = "test_value" # Add request body if required + # Import and create proper request model instance + from xdk.community_notes.models import CreateRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = CreateRequest() # Call the method try: - method = getattr(self.community_notes_client, "delete_notes") + method = getattr(self.community_notes_client, "create") result = method(**kwargs) # Verify the request was made - mock_session.delete.assert_called_once() + mock_session.post.assert_called_once() # Verify request structure - call_args = mock_session.delete.call_args + call_args = mock_session.post.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/notes/{id}" + expected_path = "/2/notes" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -152,12 +149,12 @@ def test_delete_notes_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for delete_notes: {e}") + pytest.fail(f"Contract test failed for create: {e}") - def test_delete_notes_required_parameters(self): - """Test that delete_notes handles parameters correctly.""" - method = getattr(self.community_notes_client, "delete_notes") + def test_create_required_parameters(self): + """Test that create handles parameters correctly.""" + method = getattr(self.community_notes_client, "create") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -165,14 +162,14 @@ def test_delete_notes_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response + mock_session.post.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_delete_notes_response_structure(self): - """Test delete_notes response structure validation.""" + def test_create_response_structure(self): + """Test create response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -182,13 +179,16 @@ def test_delete_notes_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["id"] = "test" # Add request body if required + # Import and create proper request model instance + from xdk.community_notes.models import CreateRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = CreateRequest() # Call method and verify response structure - method = getattr(self.community_notes_client, "delete_notes") + method = getattr(self.community_notes_client, "create") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -200,8 +200,8 @@ def test_delete_notes_response_structure(self): ) - def test_search_notes_written_request_structure(self): - """Test search_notes_written request structure.""" + def test_search_written_request_structure(self): + """Test search_written request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -218,7 +218,7 @@ def test_search_notes_written_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.community_notes_client, "search_notes_written") + method = getattr(self.community_notes_client, "search_written") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -237,12 +237,12 @@ def test_search_notes_written_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for search_notes_written: {e}") + pytest.fail(f"Contract test failed for search_written: {e}") - def test_search_notes_written_required_parameters(self): - """Test that search_notes_written handles parameters correctly.""" - method = getattr(self.community_notes_client, "search_notes_written") + def test_search_written_required_parameters(self): + """Test that search_written handles parameters correctly.""" + method = getattr(self.community_notes_client, "search_written") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -256,8 +256,8 @@ def test_search_notes_written_required_parameters(self): method() - def test_search_notes_written_response_structure(self): - """Test search_notes_written response structure validation.""" + def test_search_written_response_structure(self): + """Test search_written response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -273,7 +273,7 @@ def test_search_notes_written_response_structure(self): kwargs["test_mode"] = True # Add request body if required # Call method and verify response structure - method = getattr(self.community_notes_client, "search_notes_written") + method = getattr(self.community_notes_client, "search_written") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -285,8 +285,8 @@ def test_search_notes_written_response_structure(self): ) - def test_search_for_eligible_posts_request_structure(self): - """Test search_for_eligible_posts request structure.""" + def test_delete_request_structure(self): + """Test delete request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -295,27 +295,25 @@ def test_search_for_eligible_posts_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["test_mode"] = True + kwargs["id"] = "test_value" # Add request body if required # Call the method try: - method = getattr( - self.community_notes_client, "search_for_eligible_posts" - ) + method = getattr(self.community_notes_client, "delete") result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.delete.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.delete.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/notes/search/posts_eligible_for_notes" + expected_path = "/2/notes/{id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -324,12 +322,12 @@ def test_search_for_eligible_posts_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for search_for_eligible_posts: {e}") + pytest.fail(f"Contract test failed for delete: {e}") - def test_search_for_eligible_posts_required_parameters(self): - """Test that search_for_eligible_posts handles parameters correctly.""" - method = getattr(self.community_notes_client, "search_for_eligible_posts") + def test_delete_required_parameters(self): + """Test that delete handles parameters correctly.""" + method = getattr(self.community_notes_client, "delete") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -337,14 +335,14 @@ def test_search_for_eligible_posts_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_search_for_eligible_posts_response_structure(self): - """Test search_for_eligible_posts response structure validation.""" + def test_delete_response_structure(self): + """Test delete response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -354,13 +352,13 @@ def test_search_for_eligible_posts_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["test_mode"] = True + kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.community_notes_client, "search_for_eligible_posts") + method = getattr(self.community_notes_client, "delete") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed diff --git a/xdk/python/tests/community_notes/test_generic.py b/xdk/python/tests/community_notes/test_generic.py index 6c7b8a17..4db701f3 100644 --- a/xdk/python/tests/community_notes/test_generic.py +++ b/xdk/python/tests/community_notes/test_generic.py @@ -1,5 +1,5 @@ """ -Auto-generated generic tests for Community_Notes client. +Auto-generated generic tests for {"class_name": "CommunityNotes", "display_name": "community notes", "import_name": "community_notes", "original": ["community", "notes"], "property_name": "community_notes"} client. This module contains general tests that validate the overall client functionality, imports, and error handling that don't need to be diff --git a/xdk/python/tests/community_notes/test_pagination.py b/xdk/python/tests/community_notes/test_pagination.py index ca7cc6ea..82118f10 100644 --- a/xdk/python/tests/community_notes/test_pagination.py +++ b/xdk/python/tests/community_notes/test_pagination.py @@ -1,5 +1,5 @@ """ -Auto-generated pagination tests for Community_Notes client. +Auto-generated pagination tests for {"class_name": "CommunityNotes", "display_name": "community notes", "import_name": "community_notes", "original": ["community", "notes"], "property_name": "community_notes"} client. This module contains tests that validate pagination functionality using the Cursor class for methods that support pagination. @@ -23,20 +23,20 @@ def setup_class(self): self.community_notes_client = getattr(self.client, "community_notes") - def test_search_notes_written_cursor_creation(self): - """Test that search_notes_written can be used with Cursor.""" - method = getattr(self.community_notes_client, "search_notes_written") + def test_search_eligible_posts_cursor_creation(self): + """Test that search_eligible_posts can be used with Cursor.""" + method = getattr(self.community_notes_client, "search_eligible_posts") # Should be able to create cursor without error try: test_cursor = cursor(method, test_mode=True, max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method searchNotesWritten should support pagination") + pytest.fail(f"Method search_eligible_posts should support pagination") - def test_search_notes_written_cursor_pages(self): - """Test pagination with pages() for search_notes_written.""" + def test_search_eligible_posts_cursor_pages(self): + """Test pagination with pages() for search_eligible_posts.""" with patch.object(self.client, "session") as mock_session: # Mock first page response first_page_response = Mock() @@ -57,7 +57,7 @@ def test_search_notes_written_cursor_pages(self): # Return different responses for consecutive calls mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.community_notes_client, "search_notes_written") + method = getattr(self.community_notes_client, "search_eligible_posts") test_cursor = cursor(method, test_mode=True, max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" @@ -73,8 +73,8 @@ def test_search_notes_written_cursor_pages(self): assert len(second_data) == 1, "Second page should have 1 item" - def test_search_notes_written_cursor_items(self): - """Test pagination with items() for search_notes_written.""" + def test_search_eligible_posts_cursor_items(self): + """Test pagination with items() for search_eligible_posts.""" with patch.object(self.client, "session") as mock_session: # Mock response with paginated data mock_response = Mock() @@ -93,7 +93,7 @@ def test_search_notes_written_cursor_items(self): mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.community_notes_client, "search_notes_written") + method = getattr(self.community_notes_client, "search_eligible_posts") test_cursor = cursor(method, test_mode=True, max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items assert len(items) == 3, f"Should get 3 items, got {len(items)}" @@ -104,15 +104,15 @@ def test_search_notes_written_cursor_items(self): ), "Items should have 'id' field" - def test_search_notes_written_pagination_parameters(self): - """Test that pagination parameters are handled correctly for search_notes_written.""" + def test_search_eligible_posts_pagination_parameters(self): + """Test that pagination parameters are handled correctly for search_eligible_posts.""" with patch.object(self.client, "session") as mock_session: mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.community_notes_client, "search_notes_written") + method = getattr(self.community_notes_client, "search_eligible_posts") # Test with max_results parameter test_cursor = cursor(method, test_mode=True, max_results=5) list(test_cursor.pages(1)) # Trigger one request @@ -165,20 +165,20 @@ def test_search_notes_written_pagination_parameters(self): ), "Pagination token should be passed correctly" - def test_search_for_eligible_posts_cursor_creation(self): - """Test that search_for_eligible_posts can be used with Cursor.""" - method = getattr(self.community_notes_client, "search_for_eligible_posts") + def test_search_written_cursor_creation(self): + """Test that search_written can be used with Cursor.""" + method = getattr(self.community_notes_client, "search_written") # Should be able to create cursor without error try: test_cursor = cursor(method, test_mode=True, max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method searchForEligiblePosts should support pagination") + pytest.fail(f"Method search_written should support pagination") - def test_search_for_eligible_posts_cursor_pages(self): - """Test pagination with pages() for search_for_eligible_posts.""" + def test_search_written_cursor_pages(self): + """Test pagination with pages() for search_written.""" with patch.object(self.client, "session") as mock_session: # Mock first page response first_page_response = Mock() @@ -199,7 +199,7 @@ def test_search_for_eligible_posts_cursor_pages(self): # Return different responses for consecutive calls mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.community_notes_client, "search_for_eligible_posts") + method = getattr(self.community_notes_client, "search_written") test_cursor = cursor(method, test_mode=True, max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" @@ -215,8 +215,8 @@ def test_search_for_eligible_posts_cursor_pages(self): assert len(second_data) == 1, "Second page should have 1 item" - def test_search_for_eligible_posts_cursor_items(self): - """Test pagination with items() for search_for_eligible_posts.""" + def test_search_written_cursor_items(self): + """Test pagination with items() for search_written.""" with patch.object(self.client, "session") as mock_session: # Mock response with paginated data mock_response = Mock() @@ -235,7 +235,7 @@ def test_search_for_eligible_posts_cursor_items(self): mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.community_notes_client, "search_for_eligible_posts") + method = getattr(self.community_notes_client, "search_written") test_cursor = cursor(method, test_mode=True, max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items assert len(items) == 3, f"Should get 3 items, got {len(items)}" @@ -246,15 +246,15 @@ def test_search_for_eligible_posts_cursor_items(self): ), "Items should have 'id' field" - def test_search_for_eligible_posts_pagination_parameters(self): - """Test that pagination parameters are handled correctly for search_for_eligible_posts.""" + def test_search_written_pagination_parameters(self): + """Test that pagination parameters are handled correctly for search_written.""" with patch.object(self.client, "session") as mock_session: mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.community_notes_client, "search_for_eligible_posts") + method = getattr(self.community_notes_client, "search_written") # Test with max_results parameter test_cursor = cursor(method, test_mode=True, max_results=5) list(test_cursor.pages(1)) # Trigger one request @@ -317,7 +317,7 @@ def test_pagination_edge_cases(self): empty_response.raise_for_status.return_value = None mock_session.get.return_value = empty_response # Pick first paginatable method for testing - method = getattr(self.community_notes_client, "search_notes_written") + method = getattr(self.community_notes_client, "search_eligible_posts") test_cursor = cursor(method, test_mode=True, max_results=10) # Should handle empty responses gracefully pages = list(test_cursor.pages(1)) diff --git a/xdk/python/tests/community_notes/test_structure.py b/xdk/python/tests/community_notes/test_structure.py index 38381d55..a8a8dbf5 100644 --- a/xdk/python/tests/community_notes/test_structure.py +++ b/xdk/python/tests/community_notes/test_structure.py @@ -1,8 +1,8 @@ """ -Auto-generated structural tests for Community_Notes client. +Auto-generated structural tests for {"class_name": "CommunityNotes", "display_name": "community notes", "import_name": "community_notes", "original": ["community", "notes"], "property_name": "community_notes"} client. This module contains tests that validate the structure and API surface -of the Community_Notes client. These tests ensure that all expected methods +of the {"class_name": "CommunityNotes", "display_name": "community notes", "import_name": "community_notes", "original": ["community", "notes"], "property_name": "community_notes"} client. These tests ensure that all expected methods exist and have the correct signatures. Generated automatically - do not edit manually. @@ -25,31 +25,38 @@ def setup_class(self): self.community_notes_client = getattr(self.client, "community_notes") - def test_create_notes_exists(self): - """Test that create_notes method exists with correct signature.""" + def test_search_eligible_posts_exists(self): + """Test that search_eligible_posts method exists with correct signature.""" # Check method exists - method = getattr(CommunityNotesClient, "create_notes", None) + method = getattr(CommunityNotesClient, "search_eligible_posts", None) assert ( method is not None - ), f"Method create_notes does not exist on CommunityNotesClient" + ), f"Method search_eligible_posts does not exist on CommunityNotesClient" # Check method is callable - assert callable(method), f"create_notes is not callable" + assert callable(method), f"search_eligible_posts is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"create_notes should have at least 'self' parameter" + assert ( + len(params) >= 1 + ), f"search_eligible_posts should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [] + required_params = [ + "test_mode", + ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from create_notes" + ), f"Required parameter '{required_param}' missing from search_eligible_posts" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "pagination_token", + "max_results", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -58,41 +65,58 @@ def test_create_notes_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_create_notes_return_annotation(self): - """Test that create_notes has proper return type annotation.""" - method = getattr(CommunityNotesClient, "create_notes") + def test_search_eligible_posts_return_annotation(self): + """Test that search_eligible_posts has proper return type annotation.""" + method = getattr(CommunityNotesClient, "search_eligible_posts") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method create_notes should have return type annotation" + ), f"Method search_eligible_posts should have return type annotation" + + + def test_search_eligible_posts_pagination_params(self): + """Test that search_eligible_posts has pagination parameters.""" + method = getattr(CommunityNotesClient, "search_eligible_posts") + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have pagination-related parameters + pagination_params = [ + "pagination_token", + "max_results", + "next_token", + "cursor", + "limit", + ] + has_pagination_param = any(param in params for param in pagination_params) + assert ( + has_pagination_param + ), f"Paginated method search_eligible_posts should have pagination parameters" - def test_delete_notes_exists(self): - """Test that delete_notes method exists with correct signature.""" + def test_create_exists(self): + """Test that create method exists with correct signature.""" # Check method exists - method = getattr(CommunityNotesClient, "delete_notes", None) + method = getattr(CommunityNotesClient, "create", None) assert ( method is not None - ), f"Method delete_notes does not exist on CommunityNotesClient" + ), f"Method create does not exist on CommunityNotesClient" # Check method is callable - assert callable(method), f"delete_notes is not callable" + assert callable(method), f"create is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"delete_notes should have at least 'self' parameter" + assert len(params) >= 1, f"create should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] + required_params = [] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from delete_notes" + ), f"Required parameter '{required_param}' missing from create" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -103,32 +127,30 @@ def test_delete_notes_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_delete_notes_return_annotation(self): - """Test that delete_notes has proper return type annotation.""" - method = getattr(CommunityNotesClient, "delete_notes") + def test_create_return_annotation(self): + """Test that create has proper return type annotation.""" + method = getattr(CommunityNotesClient, "create") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method delete_notes should have return type annotation" + ), f"Method create should have return type annotation" - def test_search_notes_written_exists(self): - """Test that search_notes_written method exists with correct signature.""" + def test_search_written_exists(self): + """Test that search_written method exists with correct signature.""" # Check method exists - method = getattr(CommunityNotesClient, "search_notes_written", None) + method = getattr(CommunityNotesClient, "search_written", None) assert ( method is not None - ), f"Method search_notes_written does not exist on CommunityNotesClient" + ), f"Method search_written does not exist on CommunityNotesClient" # Check method is callable - assert callable(method), f"search_notes_written is not callable" + assert callable(method), f"search_written is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"search_notes_written should have at least 'self' parameter" + assert len(params) >= 1, f"search_written should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -139,7 +161,7 @@ def test_search_notes_written_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from search_notes_written" + ), f"Required parameter '{required_param}' missing from search_written" # Check optional parameters have defaults (excluding 'self') optional_params = [ "pagination_token", @@ -153,19 +175,19 @@ def test_search_notes_written_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_search_notes_written_return_annotation(self): - """Test that search_notes_written has proper return type annotation.""" - method = getattr(CommunityNotesClient, "search_notes_written") + def test_search_written_return_annotation(self): + """Test that search_written has proper return type annotation.""" + method = getattr(CommunityNotesClient, "search_written") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method search_notes_written should have return type annotation" + ), f"Method search_written should have return type annotation" - def test_search_notes_written_pagination_params(self): - """Test that search_notes_written has pagination parameters.""" - method = getattr(CommunityNotesClient, "search_notes_written") + def test_search_written_pagination_params(self): + """Test that search_written has pagination parameters.""" + method = getattr(CommunityNotesClient, "search_written") sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have pagination-related parameters @@ -179,41 +201,36 @@ def test_search_notes_written_pagination_params(self): has_pagination_param = any(param in params for param in pagination_params) assert ( has_pagination_param - ), f"Paginated method search_notes_written should have pagination parameters" + ), f"Paginated method search_written should have pagination parameters" - def test_search_for_eligible_posts_exists(self): - """Test that search_for_eligible_posts method exists with correct signature.""" + def test_delete_exists(self): + """Test that delete method exists with correct signature.""" # Check method exists - method = getattr(CommunityNotesClient, "search_for_eligible_posts", None) + method = getattr(CommunityNotesClient, "delete", None) assert ( method is not None - ), f"Method search_for_eligible_posts does not exist on CommunityNotesClient" + ), f"Method delete does not exist on CommunityNotesClient" # Check method is callable - assert callable(method), f"search_for_eligible_posts is not callable" + assert callable(method), f"delete is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"search_for_eligible_posts should have at least 'self' parameter" + assert len(params) >= 1, f"delete should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "test_mode", + "id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from search_for_eligible_posts" + ), f"Required parameter '{required_param}' missing from delete" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "pagination_token", - "max_results", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -222,42 +239,23 @@ def test_search_for_eligible_posts_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_search_for_eligible_posts_return_annotation(self): - """Test that search_for_eligible_posts has proper return type annotation.""" - method = getattr(CommunityNotesClient, "search_for_eligible_posts") + def test_delete_return_annotation(self): + """Test that delete has proper return type annotation.""" + method = getattr(CommunityNotesClient, "delete") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method search_for_eligible_posts should have return type annotation" - - - def test_search_for_eligible_posts_pagination_params(self): - """Test that search_for_eligible_posts has pagination parameters.""" - method = getattr(CommunityNotesClient, "search_for_eligible_posts") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method search_for_eligible_posts should have pagination parameters" + ), f"Method delete should have return type annotation" def test_all_expected_methods_exist(self): """Test that all expected methods exist on the client.""" expected_methods = [ - "create_notes", - "delete_notes", - "search_notes_written", - "search_for_eligible_posts", + "search_eligible_posts", + "create", + "search_written", + "delete", ] for expected_method in expected_methods: assert hasattr( diff --git a/xdk/python/tests/compliance/test_contracts.py b/xdk/python/tests/compliance/test_contracts.py index be3346d3..51da2743 100644 --- a/xdk/python/tests/compliance/test_contracts.py +++ b/xdk/python/tests/compliance/test_contracts.py @@ -1,8 +1,8 @@ """ -Auto-generated contract tests for Compliance client. +Auto-generated contract tests for {"class_name": "Compliance", "display_name": "compliance", "import_name": "compliance", "original": ["compliance"], "property_name": "compliance"} client. This module contains tests that validate the request/response contracts -of the Compliance client against the OpenAPI specification. +of the {"class_name": "Compliance", "display_name": "compliance", "import_name": "compliance", "original": ["compliance"], "property_name": "compliance"} client against the OpenAPI specification. Generated automatically - do not edit manually. """ @@ -24,8 +24,8 @@ def setup_class(self): self.compliance_client = getattr(self.client, "compliance") - def test_get_compliance_jobs_by_id_request_structure(self): - """Test get_compliance_jobs_by_id request structure.""" + def test_get_jobs_by_id_request_structure(self): + """Test get_jobs_by_id request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -42,7 +42,7 @@ def test_get_compliance_jobs_by_id_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.compliance_client, "get_compliance_jobs_by_id") + method = getattr(self.compliance_client, "get_jobs_by_id") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -61,12 +61,12 @@ def test_get_compliance_jobs_by_id_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_compliance_jobs_by_id: {e}") + pytest.fail(f"Contract test failed for get_jobs_by_id: {e}") - def test_get_compliance_jobs_by_id_required_parameters(self): - """Test that get_compliance_jobs_by_id handles parameters correctly.""" - method = getattr(self.compliance_client, "get_compliance_jobs_by_id") + def test_get_jobs_by_id_required_parameters(self): + """Test that get_jobs_by_id handles parameters correctly.""" + method = getattr(self.compliance_client, "get_jobs_by_id") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -80,8 +80,8 @@ def test_get_compliance_jobs_by_id_required_parameters(self): method() - def test_get_compliance_jobs_by_id_response_structure(self): - """Test get_compliance_jobs_by_id response structure validation.""" + def test_get_jobs_by_id_response_structure(self): + """Test get_jobs_by_id response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -97,7 +97,7 @@ def test_get_compliance_jobs_by_id_response_structure(self): kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.compliance_client, "get_compliance_jobs_by_id") + method = getattr(self.compliance_client, "get_jobs_by_id") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -109,176 +109,8 @@ def test_get_compliance_jobs_by_id_response_structure(self): ) - def test_stream_likes_compliance_request_structure(self): - """Test stream_likes_compliance request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.compliance_client, "stream_likes_compliance") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/likes/compliance/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_likes_compliance: {e}") - - - def test_stream_likes_compliance_required_parameters(self): - """Test that stream_likes_compliance handles parameters correctly.""" - method = getattr(self.compliance_client, "stream_likes_compliance") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_stream_likes_compliance_response_structure(self): - """Test stream_likes_compliance response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.compliance_client, "stream_likes_compliance") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_compliance_request_structure(self): - """Test stream_posts_compliance request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.compliance_client, "stream_posts_compliance") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/compliance/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_compliance: {e}") - - - def test_stream_posts_compliance_required_parameters(self): - """Test that stream_posts_compliance handles parameters correctly.""" - method = getattr(self.compliance_client, "stream_posts_compliance") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_compliance_response_structure(self): - """Test stream_posts_compliance response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.compliance_client, "stream_posts_compliance") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_compliance_jobs_request_structure(self): - """Test get_compliance_jobs request structure.""" + def test_get_jobs_request_structure(self): + """Test get_jobs request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -295,7 +127,7 @@ def test_get_compliance_jobs_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.compliance_client, "get_compliance_jobs") + method = getattr(self.compliance_client, "get_jobs") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -314,12 +146,12 @@ def test_get_compliance_jobs_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_compliance_jobs: {e}") + pytest.fail(f"Contract test failed for get_jobs: {e}") - def test_get_compliance_jobs_required_parameters(self): - """Test that get_compliance_jobs handles parameters correctly.""" - method = getattr(self.compliance_client, "get_compliance_jobs") + def test_get_jobs_required_parameters(self): + """Test that get_jobs handles parameters correctly.""" + method = getattr(self.compliance_client, "get_jobs") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -333,8 +165,8 @@ def test_get_compliance_jobs_required_parameters(self): method() - def test_get_compliance_jobs_response_structure(self): - """Test get_compliance_jobs response structure validation.""" + def test_get_jobs_response_structure(self): + """Test get_jobs response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -350,7 +182,7 @@ def test_get_compliance_jobs_response_structure(self): kwargs["type"] = "test_value" # Add request body if required # Call method and verify response structure - method = getattr(self.compliance_client, "get_compliance_jobs") + method = getattr(self.compliance_client, "get_jobs") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -362,8 +194,8 @@ def test_get_compliance_jobs_response_structure(self): ) - def test_create_compliance_jobs_request_structure(self): - """Test create_compliance_jobs request structure.""" + def test_create_jobs_request_structure(self): + """Test create_jobs request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -378,12 +210,12 @@ def test_create_compliance_jobs_request_structure(self): # Add required parameters # Add request body if required # Import and create proper request model instance - from xdk.compliance.models import CreateComplianceJobsRequest + from xdk.compliance.models import CreateJobsRequest # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateComplianceJobsRequest() + kwargs["body"] = CreateJobsRequest() # Call the method try: - method = getattr(self.compliance_client, "create_compliance_jobs") + method = getattr(self.compliance_client, "create_jobs") result = method(**kwargs) # Verify the request was made mock_session.post.assert_called_once() @@ -402,12 +234,12 @@ def test_create_compliance_jobs_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for create_compliance_jobs: {e}") + pytest.fail(f"Contract test failed for create_jobs: {e}") - def test_create_compliance_jobs_required_parameters(self): - """Test that create_compliance_jobs handles parameters correctly.""" - method = getattr(self.compliance_client, "create_compliance_jobs") + def test_create_jobs_required_parameters(self): + """Test that create_jobs handles parameters correctly.""" + method = getattr(self.compliance_client, "create_jobs") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -421,8 +253,8 @@ def test_create_compliance_jobs_required_parameters(self): method() - def test_create_compliance_jobs_response_structure(self): - """Test create_compliance_jobs response structure validation.""" + def test_create_jobs_response_structure(self): + """Test create_jobs response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -437,179 +269,11 @@ def test_create_compliance_jobs_response_structure(self): kwargs = {} # Add request body if required # Import and create proper request model instance - from xdk.compliance.models import CreateComplianceJobsRequest + from xdk.compliance.models import CreateJobsRequest # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateComplianceJobsRequest() - # Call method and verify response structure - method = getattr(self.compliance_client, "create_compliance_jobs") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_users_compliance_request_structure(self): - """Test stream_users_compliance request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.compliance_client, "stream_users_compliance") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/compliance/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_users_compliance: {e}") - - - def test_stream_users_compliance_required_parameters(self): - """Test that stream_users_compliance handles parameters correctly.""" - method = getattr(self.compliance_client, "stream_users_compliance") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_users_compliance_response_structure(self): - """Test stream_users_compliance response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.compliance_client, "stream_users_compliance") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_labels_compliance_request_structure(self): - """Test stream_labels_compliance request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.compliance_client, "stream_labels_compliance") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/label/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_labels_compliance: {e}") - - - def test_stream_labels_compliance_required_parameters(self): - """Test that stream_labels_compliance handles parameters correctly.""" - method = getattr(self.compliance_client, "stream_labels_compliance") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_stream_labels_compliance_response_structure(self): - """Test stream_labels_compliance response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required + kwargs["body"] = CreateJobsRequest() # Call method and verify response structure - method = getattr(self.compliance_client, "stream_labels_compliance") + method = getattr(self.compliance_client, "create_jobs") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed diff --git a/xdk/python/tests/compliance/test_generic.py b/xdk/python/tests/compliance/test_generic.py index 73c26a37..30257533 100644 --- a/xdk/python/tests/compliance/test_generic.py +++ b/xdk/python/tests/compliance/test_generic.py @@ -1,5 +1,5 @@ """ -Auto-generated generic tests for Compliance client. +Auto-generated generic tests for {"class_name": "Compliance", "display_name": "compliance", "import_name": "compliance", "original": ["compliance"], "property_name": "compliance"} client. This module contains general tests that validate the overall client functionality, imports, and error handling that don't need to be diff --git a/xdk/python/tests/compliance/test_structure.py b/xdk/python/tests/compliance/test_structure.py index 3cce7b01..76815167 100644 --- a/xdk/python/tests/compliance/test_structure.py +++ b/xdk/python/tests/compliance/test_structure.py @@ -1,8 +1,8 @@ """ -Auto-generated structural tests for Compliance client. +Auto-generated structural tests for {"class_name": "Compliance", "display_name": "compliance", "import_name": "compliance", "original": ["compliance"], "property_name": "compliance"} client. This module contains tests that validate the structure and API surface -of the Compliance client. These tests ensure that all expected methods +of the {"class_name": "Compliance", "display_name": "compliance", "import_name": "compliance", "original": ["compliance"], "property_name": "compliance"} client. These tests ensure that all expected methods exist and have the correct signatures. Generated automatically - do not edit manually. @@ -25,22 +25,20 @@ def setup_class(self): self.compliance_client = getattr(self.client, "compliance") - def test_get_compliance_jobs_by_id_exists(self): - """Test that get_compliance_jobs_by_id method exists with correct signature.""" + def test_get_jobs_by_id_exists(self): + """Test that get_jobs_by_id method exists with correct signature.""" # Check method exists - method = getattr(ComplianceClient, "get_compliance_jobs_by_id", None) + method = getattr(ComplianceClient, "get_jobs_by_id", None) assert ( method is not None - ), f"Method get_compliance_jobs_by_id does not exist on ComplianceClient" + ), f"Method get_jobs_by_id does not exist on ComplianceClient" # Check method is callable - assert callable(method), f"get_compliance_jobs_by_id is not callable" + assert callable(method), f"get_jobs_by_id is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_compliance_jobs_by_id should have at least 'self' parameter" + assert len(params) >= 1, f"get_jobs_by_id should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -51,7 +49,7 @@ def test_get_compliance_jobs_by_id_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_compliance_jobs_by_id" + ), f"Required parameter '{required_param}' missing from get_jobs_by_id" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -62,132 +60,28 @@ def test_get_compliance_jobs_by_id_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_compliance_jobs_by_id_return_annotation(self): - """Test that get_compliance_jobs_by_id has proper return type annotation.""" - method = getattr(ComplianceClient, "get_compliance_jobs_by_id") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_compliance_jobs_by_id should have return type annotation" - - - def test_stream_likes_compliance_exists(self): - """Test that stream_likes_compliance method exists with correct signature.""" - # Check method exists - method = getattr(ComplianceClient, "stream_likes_compliance", None) - assert ( - method is not None - ), f"Method stream_likes_compliance does not exist on ComplianceClient" - # Check method is callable - assert callable(method), f"stream_likes_compliance is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_likes_compliance should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_likes_compliance" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_likes_compliance_return_annotation(self): - """Test that stream_likes_compliance has proper return type annotation.""" - method = getattr(ComplianceClient, "stream_likes_compliance") + def test_get_jobs_by_id_return_annotation(self): + """Test that get_jobs_by_id has proper return type annotation.""" + method = getattr(ComplianceClient, "get_jobs_by_id") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_likes_compliance should have return type annotation" + ), f"Method get_jobs_by_id should have return type annotation" - def test_stream_posts_compliance_exists(self): - """Test that stream_posts_compliance method exists with correct signature.""" + def test_get_jobs_exists(self): + """Test that get_jobs method exists with correct signature.""" # Check method exists - method = getattr(ComplianceClient, "stream_posts_compliance", None) - assert ( - method is not None - ), f"Method stream_posts_compliance does not exist on ComplianceClient" + method = getattr(ComplianceClient, "get_jobs", None) + assert method is not None, f"Method get_jobs does not exist on ComplianceClient" # Check method is callable - assert callable(method), f"stream_posts_compliance is not callable" + assert callable(method), f"get_jobs is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_compliance should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_compliance" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_compliance_return_annotation(self): - """Test that stream_posts_compliance has proper return type annotation.""" - method = getattr(ComplianceClient, "stream_posts_compliance") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_compliance should have return type annotation" - - - def test_get_compliance_jobs_exists(self): - """Test that get_compliance_jobs method exists with correct signature.""" - # Check method exists - method = getattr(ComplianceClient, "get_compliance_jobs", None) - assert ( - method is not None - ), f"Method get_compliance_jobs does not exist on ComplianceClient" - # Check method is callable - assert callable(method), f"get_compliance_jobs is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_compliance_jobs should have at least 'self' parameter" + assert len(params) >= 1, f"get_jobs should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -198,7 +92,7 @@ def test_get_compliance_jobs_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_compliance_jobs" + ), f"Required parameter '{required_param}' missing from get_jobs" # Check optional parameters have defaults (excluding 'self') optional_params = [ "status", @@ -211,32 +105,30 @@ def test_get_compliance_jobs_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_compliance_jobs_return_annotation(self): - """Test that get_compliance_jobs has proper return type annotation.""" - method = getattr(ComplianceClient, "get_compliance_jobs") + def test_get_jobs_return_annotation(self): + """Test that get_jobs has proper return type annotation.""" + method = getattr(ComplianceClient, "get_jobs") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_compliance_jobs should have return type annotation" + ), f"Method get_jobs should have return type annotation" - def test_create_compliance_jobs_exists(self): - """Test that create_compliance_jobs method exists with correct signature.""" + def test_create_jobs_exists(self): + """Test that create_jobs method exists with correct signature.""" # Check method exists - method = getattr(ComplianceClient, "create_compliance_jobs", None) + method = getattr(ComplianceClient, "create_jobs", None) assert ( method is not None - ), f"Method create_compliance_jobs does not exist on ComplianceClient" + ), f"Method create_jobs does not exist on ComplianceClient" # Check method is callable - assert callable(method), f"create_compliance_jobs is not callable" + assert callable(method), f"create_jobs is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"create_compliance_jobs should have at least 'self' parameter" + assert len(params) >= 1, f"create_jobs should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -245,7 +137,7 @@ def test_create_compliance_jobs_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from create_compliance_jobs" + ), f"Required parameter '{required_param}' missing from create_jobs" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -256,126 +148,22 @@ def test_create_compliance_jobs_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_create_compliance_jobs_return_annotation(self): - """Test that create_compliance_jobs has proper return type annotation.""" - method = getattr(ComplianceClient, "create_compliance_jobs") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method create_compliance_jobs should have return type annotation" - - - def test_stream_users_compliance_exists(self): - """Test that stream_users_compliance method exists with correct signature.""" - # Check method exists - method = getattr(ComplianceClient, "stream_users_compliance", None) - assert ( - method is not None - ), f"Method stream_users_compliance does not exist on ComplianceClient" - # Check method is callable - assert callable(method), f"stream_users_compliance is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_users_compliance should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_users_compliance" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_users_compliance_return_annotation(self): - """Test that stream_users_compliance has proper return type annotation.""" - method = getattr(ComplianceClient, "stream_users_compliance") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_users_compliance should have return type annotation" - - - def test_stream_labels_compliance_exists(self): - """Test that stream_labels_compliance method exists with correct signature.""" - # Check method exists - method = getattr(ComplianceClient, "stream_labels_compliance", None) - assert ( - method is not None - ), f"Method stream_labels_compliance does not exist on ComplianceClient" - # Check method is callable - assert callable(method), f"stream_labels_compliance is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_labels_compliance should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_labels_compliance" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_labels_compliance_return_annotation(self): - """Test that stream_labels_compliance has proper return type annotation.""" - method = getattr(ComplianceClient, "stream_labels_compliance") + def test_create_jobs_return_annotation(self): + """Test that create_jobs has proper return type annotation.""" + method = getattr(ComplianceClient, "create_jobs") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_labels_compliance should have return type annotation" + ), f"Method create_jobs should have return type annotation" def test_all_expected_methods_exist(self): """Test that all expected methods exist on the client.""" expected_methods = [ - "get_compliance_jobs_by_id", - "stream_likes_compliance", - "stream_posts_compliance", - "get_compliance_jobs", - "create_compliance_jobs", - "stream_users_compliance", - "stream_labels_compliance", + "get_jobs_by_id", + "get_jobs", + "create_jobs", ] for expected_method in expected_methods: assert hasattr( diff --git a/xdk/python/tests/conftest.py b/xdk/python/tests/conftest.py deleted file mode 100644 index c5cfb0e3..00000000 --- a/xdk/python/tests/conftest.py +++ /dev/null @@ -1,21 +0,0 @@ -"""Test configuration and fixtures.""" - -import pytest -from unittest.mock import Mock -from xdk import Client - - -@pytest.fixture - - -def mock_client(): - """Provide a mock client for testing.""" - return Client(base_url="https://api.example.com") - - -@pytest.fixture - - -def mock_session(): - """Provide a mock session for HTTP requests.""" - return Mock() diff --git a/xdk/python/tests/connection/test_contracts.py b/xdk/python/tests/connection/test_contracts.py index 27fc0f9c..8f332cf5 100644 --- a/xdk/python/tests/connection/test_contracts.py +++ b/xdk/python/tests/connection/test_contracts.py @@ -1,8 +1,8 @@ """ -Auto-generated contract tests for Connection client. +Auto-generated contract tests for {"class_name": "Connection", "display_name": "connection", "import_name": "connection", "original": ["connection"], "property_name": "connection"} client. This module contains tests that validate the request/response contracts -of the Connection client against the OpenAPI specification. +of the {"class_name": "Connection", "display_name": "connection", "import_name": "connection", "original": ["connection"], "property_name": "connection"} client against the OpenAPI specification. Generated automatically - do not edit manually. """ diff --git a/xdk/python/tests/connection/test_generic.py b/xdk/python/tests/connection/test_generic.py index df65e008..b49585c6 100644 --- a/xdk/python/tests/connection/test_generic.py +++ b/xdk/python/tests/connection/test_generic.py @@ -1,5 +1,5 @@ """ -Auto-generated generic tests for Connection client. +Auto-generated generic tests for {"class_name": "Connection", "display_name": "connection", "import_name": "connection", "original": ["connection"], "property_name": "connection"} client. This module contains general tests that validate the overall client functionality, imports, and error handling that don't need to be diff --git a/xdk/python/tests/connection/test_structure.py b/xdk/python/tests/connection/test_structure.py index ebf7e1df..c161c6c4 100644 --- a/xdk/python/tests/connection/test_structure.py +++ b/xdk/python/tests/connection/test_structure.py @@ -1,8 +1,8 @@ """ -Auto-generated structural tests for Connection client. +Auto-generated structural tests for {"class_name": "Connection", "display_name": "connection", "import_name": "connection", "original": ["connection"], "property_name": "connection"} client. This module contains tests that validate the structure and API surface -of the Connection client. These tests ensure that all expected methods +of the {"class_name": "Connection", "display_name": "connection", "import_name": "connection", "original": ["connection"], "property_name": "connection"} client. These tests ensure that all expected methods exist and have the correct signatures. Generated automatically - do not edit manually. diff --git a/xdk/python/tests/direct_messages/test_contracts.py b/xdk/python/tests/direct_messages/test_contracts.py index 67c44e92..b8dd83f2 100644 --- a/xdk/python/tests/direct_messages/test_contracts.py +++ b/xdk/python/tests/direct_messages/test_contracts.py @@ -1,8 +1,8 @@ """ -Auto-generated contract tests for Direct_Messages client. +Auto-generated contract tests for {"class_name": "DirectMessages", "display_name": "direct messages", "import_name": "direct_messages", "original": ["direct", "messages"], "property_name": "direct_messages"} client. This module contains tests that validate the request/response contracts -of the Direct_Messages client against the OpenAPI specification. +of the {"class_name": "DirectMessages", "display_name": "direct messages", "import_name": "direct_messages", "original": ["direct", "messages"], "property_name": "direct_messages"} client against the OpenAPI specification. Generated automatically - do not edit manually. """ @@ -117,37 +117,41 @@ def test_get_dm_conversations_id_dm_events_response_structure(self): ) - def test_get_dm_events_by_participant_id_request_structure(self): - """Test get_dm_events_by_participant_id request structure.""" + def test_create_dm_by_conversation_id_request_structure(self): + """Test create_dm_by_conversation_id request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() - mock_response.status_code = 200 + mock_response.status_code = 201 mock_response.json.return_value = { "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["participant_id"] = "test_value" + kwargs["dm_conversation_id"] = "test_dm_conversation_id" # Add request body if required + # Import and create proper request model instance + from xdk.direct_messages.models import CreateDmByConversationIdRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = CreateDmByConversationIdRequest() # Call the method try: method = getattr( - self.direct_messages_client, "get_dm_events_by_participant_id" + self.direct_messages_client, "create_dm_by_conversation_id" ) result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.post.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.post.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/dm_conversations/with/{participant_id}/dm_events" + expected_path = "/2/dm_conversations/{dm_conversation_id}/messages" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -157,13 +161,13 @@ def test_get_dm_events_by_participant_id_request_structure(self): assert result is not None, "Method should return a result" except Exception as e: pytest.fail( - f"Contract test failed for get_dm_events_by_participant_id: {e}" + f"Contract test failed for create_dm_by_conversation_id: {e}" ) - def test_get_dm_events_by_participant_id_required_parameters(self): - """Test that get_dm_events_by_participant_id handles parameters correctly.""" - method = getattr(self.direct_messages_client, "get_dm_events_by_participant_id") + def test_create_dm_by_conversation_id_required_parameters(self): + """Test that create_dm_by_conversation_id handles parameters correctly.""" + method = getattr(self.direct_messages_client, "create_dm_by_conversation_id") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -171,31 +175,35 @@ def test_get_dm_events_by_participant_id_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_get_dm_events_by_participant_id_response_structure(self): - """Test get_dm_events_by_participant_id response structure validation.""" + def test_create_dm_by_conversation_id_response_structure(self): + """Test create_dm_by_conversation_id response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { "data": None, } mock_response = Mock() - mock_response.status_code = 200 + mock_response.status_code = 201 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["participant_id"] = "test" + kwargs["dm_conversation_id"] = "test_value" # Add request body if required + # Import and create proper request model instance + from xdk.direct_messages.models import CreateDmByConversationIdRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = CreateDmByConversationIdRequest() # Call method and verify response structure method = getattr( - self.direct_messages_client, "get_dm_events_by_participant_id" + self.direct_messages_client, "create_dm_by_conversation_id" ) result = method(**kwargs) # Verify response object has expected attributes @@ -208,8 +216,8 @@ def test_get_dm_events_by_participant_id_response_structure(self): ) - def test_get_dm_events_request_structure(self): - """Test get_dm_events request structure.""" + def test_get_events_by_id_request_structure(self): + """Test get_events_by_id request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -222,10 +230,11 @@ def test_get_dm_events_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters + kwargs["event_id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.direct_messages_client, "get_dm_events") + method = getattr(self.direct_messages_client, "get_events_by_id") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -235,7 +244,7 @@ def test_get_dm_events_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/dm_events" + expected_path = "/2/dm_events/{event_id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -244,27 +253,27 @@ def test_get_dm_events_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_dm_events: {e}") + pytest.fail(f"Contract test failed for get_events_by_id: {e}") - def test_get_dm_events_required_parameters(self): - """Test that get_dm_events handles parameters correctly.""" - method = getattr(self.direct_messages_client, "get_dm_events") - # No required parameters, method should be callable without args + def test_get_events_by_id_required_parameters(self): + """Test that get_events_by_id handles parameters correctly.""" + method = getattr(self.direct_messages_client, "get_events_by_id") + # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: + # Mock a 400 response (typical for missing required parameters) mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None + mock_response.status_code = 400 + mock_response.json.return_value = {"error": "Missing required parameters"} + mock_response.raise_for_status.side_effect = Exception("Bad Request") mock_session.get.return_value = mock_response - try: + # Call without required parameters should either raise locally or via server response + with pytest.raises((TypeError, ValueError, Exception)): method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - def test_get_dm_events_response_structure(self): - """Test get_dm_events response structure validation.""" + def test_get_events_by_id_response_structure(self): + """Test get_events_by_id response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -277,9 +286,10 @@ def test_get_dm_events_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} + kwargs["event_id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.direct_messages_client, "get_dm_events") + method = getattr(self.direct_messages_client, "get_events_by_id") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -291,8 +301,8 @@ def test_get_dm_events_response_structure(self): ) - def test_get_dm_events_by_id_request_structure(self): - """Test get_dm_events_by_id request structure.""" + def test_delete_dm_events_request_structure(self): + """Test delete_dm_events request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -301,7 +311,7 @@ def test_get_dm_events_by_id_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters @@ -309,12 +319,12 @@ def test_get_dm_events_by_id_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.direct_messages_client, "get_dm_events_by_id") + method = getattr(self.direct_messages_client, "delete_dm_events") result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.delete.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.delete.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") @@ -328,12 +338,12 @@ def test_get_dm_events_by_id_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_dm_events_by_id: {e}") + pytest.fail(f"Contract test failed for delete_dm_events: {e}") - def test_get_dm_events_by_id_required_parameters(self): - """Test that get_dm_events_by_id handles parameters correctly.""" - method = getattr(self.direct_messages_client, "get_dm_events_by_id") + def test_delete_dm_events_required_parameters(self): + """Test that delete_dm_events handles parameters correctly.""" + method = getattr(self.direct_messages_client, "delete_dm_events") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -341,14 +351,14 @@ def test_get_dm_events_by_id_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_get_dm_events_by_id_response_structure(self): - """Test get_dm_events_by_id response structure validation.""" + def test_delete_dm_events_response_structure(self): + """Test delete_dm_events response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -358,13 +368,13 @@ def test_get_dm_events_by_id_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["event_id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.direct_messages_client, "get_dm_events_by_id") + method = getattr(self.direct_messages_client, "delete_dm_events") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -376,8 +386,8 @@ def test_get_dm_events_by_id_response_structure(self): ) - def test_delete_dm_events_request_structure(self): - """Test delete_dm_events request structure.""" + def test_create_dm_conversations_request_structure(self): + """Test create_dm_conversations request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -386,25 +396,28 @@ def test_delete_dm_events_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["event_id"] = "test_value" # Add request body if required + # Import and create proper request model instance + from xdk.direct_messages.models import CreateDmConversationsRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = CreateDmConversationsRequest() # Call the method try: - method = getattr(self.direct_messages_client, "delete_dm_events") + method = getattr(self.direct_messages_client, "create_dm_conversations") result = method(**kwargs) # Verify the request was made - mock_session.delete.assert_called_once() + mock_session.post.assert_called_once() # Verify request structure - call_args = mock_session.delete.call_args + call_args = mock_session.post.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/dm_events/{event_id}" + expected_path = "/2/dm_conversations" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -413,12 +426,12 @@ def test_delete_dm_events_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for delete_dm_events: {e}") + pytest.fail(f"Contract test failed for create_dm_conversations: {e}") - def test_delete_dm_events_required_parameters(self): - """Test that delete_dm_events handles parameters correctly.""" - method = getattr(self.direct_messages_client, "delete_dm_events") + def test_create_dm_conversations_required_parameters(self): + """Test that create_dm_conversations handles parameters correctly.""" + method = getattr(self.direct_messages_client, "create_dm_conversations") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -426,14 +439,14 @@ def test_delete_dm_events_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response + mock_session.post.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_delete_dm_events_response_structure(self): - """Test delete_dm_events response structure validation.""" + def test_create_dm_conversations_response_structure(self): + """Test create_dm_conversations response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -443,13 +456,16 @@ def test_delete_dm_events_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["event_id"] = "test" # Add request body if required + # Import and create proper request model instance + from xdk.direct_messages.models import CreateDmConversationsRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = CreateDmConversationsRequest() # Call method and verify response structure - method = getattr(self.direct_messages_client, "delete_dm_events") + method = getattr(self.direct_messages_client, "create_dm_conversations") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -461,41 +477,37 @@ def test_delete_dm_events_response_structure(self): ) - def test_create_dm_by_participant_id_request_structure(self): - """Test create_dm_by_participant_id request structure.""" + def test_get_dm_events_by_participant_id_request_structure(self): + """Test get_dm_events_by_participant_id request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() - mock_response.status_code = 201 + mock_response.status_code = 200 mock_response.json.return_value = { "data": None, } mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters kwargs["participant_id"] = "test_value" # Add request body if required - # Import and create proper request model instance - from xdk.direct_messages.models import CreateDmByParticipantIdRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateDmByParticipantIdRequest() # Call the method try: method = getattr( - self.direct_messages_client, "create_dm_by_participant_id" + self.direct_messages_client, "get_dm_events_by_participant_id" ) result = method(**kwargs) # Verify the request was made - mock_session.post.assert_called_once() + mock_session.get.assert_called_once() # Verify request structure - call_args = mock_session.post.call_args + call_args = mock_session.get.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/dm_conversations/with/{participant_id}/messages" + expected_path = "/2/dm_conversations/with/{participant_id}/dm_events" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -505,13 +517,13 @@ def test_create_dm_by_participant_id_request_structure(self): assert result is not None, "Method should return a result" except Exception as e: pytest.fail( - f"Contract test failed for create_dm_by_participant_id: {e}" + f"Contract test failed for get_dm_events_by_participant_id: {e}" ) - def test_create_dm_by_participant_id_required_parameters(self): - """Test that create_dm_by_participant_id handles parameters correctly.""" - method = getattr(self.direct_messages_client, "create_dm_by_participant_id") + def test_get_dm_events_by_participant_id_required_parameters(self): + """Test that get_dm_events_by_participant_id handles parameters correctly.""" + method = getattr(self.direct_messages_client, "get_dm_events_by_participant_id") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -519,34 +531,32 @@ def test_create_dm_by_participant_id_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_create_dm_by_participant_id_response_structure(self): - """Test create_dm_by_participant_id response structure validation.""" + def test_get_dm_events_by_participant_id_response_structure(self): + """Test get_dm_events_by_participant_id response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { "data": None, } mock_response = Mock() - mock_response.status_code = 201 + mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["participant_id"] = "test" # Add request body if required - # Import and create proper request model instance - from xdk.direct_messages.models import CreateDmByParticipantIdRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateDmByParticipantIdRequest() # Call method and verify response structure - method = getattr(self.direct_messages_client, "create_dm_by_participant_id") + method = getattr( + self.direct_messages_client, "get_dm_events_by_participant_id" + ) result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -558,41 +568,34 @@ def test_create_dm_by_participant_id_response_structure(self): ) - def test_create_dm_by_conversation_id_request_structure(self): - """Test create_dm_by_conversation_id request structure.""" + def test_get_events_request_structure(self): + """Test get_events request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() - mock_response.status_code = 201 + mock_response.status_code = 200 mock_response.json.return_value = { "data": None, } mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["dm_conversation_id"] = "test_dm_conversation_id" # Add request body if required - # Import and create proper request model instance - from xdk.direct_messages.models import CreateDmByConversationIdRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateDmByConversationIdRequest() # Call the method try: - method = getattr( - self.direct_messages_client, "create_dm_by_conversation_id" - ) + method = getattr(self.direct_messages_client, "get_events") result = method(**kwargs) # Verify the request was made - mock_session.post.assert_called_once() + mock_session.get.assert_called_once() # Verify request structure - call_args = mock_session.post.call_args + call_args = mock_session.get.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/dm_conversations/{dm_conversation_id}/messages" + expected_path = "/2/dm_events" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -601,51 +604,42 @@ def test_create_dm_by_conversation_id_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail( - f"Contract test failed for create_dm_by_conversation_id: {e}" - ) + pytest.fail(f"Contract test failed for get_events: {e}") - def test_create_dm_by_conversation_id_required_parameters(self): - """Test that create_dm_by_conversation_id handles parameters correctly.""" - method = getattr(self.direct_messages_client, "create_dm_by_conversation_id") - # Test with missing required parameters - mock the request to avoid network calls + def test_get_events_required_parameters(self): + """Test that get_events handles parameters correctly.""" + method = getattr(self.direct_messages_client, "get_events") + # No required parameters, method should be callable without args with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): + mock_response.status_code = 200 + mock_response.json.return_value = {} + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + try: method() + except Exception as e: + pytest.fail(f"Method with no required params should be callable: {e}") - def test_create_dm_by_conversation_id_response_structure(self): - """Test create_dm_by_conversation_id response structure validation.""" + def test_get_events_response_structure(self): + """Test get_events response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { "data": None, } mock_response = Mock() - mock_response.status_code = 201 + mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["dm_conversation_id"] = "test_value" # Add request body if required - # Import and create proper request model instance - from xdk.direct_messages.models import CreateDmByConversationIdRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateDmByConversationIdRequest() # Call method and verify response structure - method = getattr( - self.direct_messages_client, "create_dm_by_conversation_id" - ) + method = getattr(self.direct_messages_client, "get_events") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -657,8 +651,8 @@ def test_create_dm_by_conversation_id_response_structure(self): ) - def test_create_dm_conversations_request_structure(self): - """Test create_dm_conversations request structure.""" + def test_create_dm_by_participant_id_request_structure(self): + """Test create_dm_by_participant_id request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -671,14 +665,17 @@ def test_create_dm_conversations_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters + kwargs["participant_id"] = "test_value" # Add request body if required # Import and create proper request model instance - from xdk.direct_messages.models import CreateDmConversationsRequest + from xdk.direct_messages.models import CreateDmByParticipantIdRequest # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateDmConversationsRequest() + kwargs["body"] = CreateDmByParticipantIdRequest() # Call the method try: - method = getattr(self.direct_messages_client, "create_dm_conversations") + method = getattr( + self.direct_messages_client, "create_dm_by_participant_id" + ) result = method(**kwargs) # Verify the request was made mock_session.post.assert_called_once() @@ -688,7 +685,7 @@ def test_create_dm_conversations_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/dm_conversations" + expected_path = "/2/dm_conversations/with/{participant_id}/messages" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -697,12 +694,14 @@ def test_create_dm_conversations_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for create_dm_conversations: {e}") + pytest.fail( + f"Contract test failed for create_dm_by_participant_id: {e}" + ) - def test_create_dm_conversations_required_parameters(self): - """Test that create_dm_conversations handles parameters correctly.""" - method = getattr(self.direct_messages_client, "create_dm_conversations") + def test_create_dm_by_participant_id_required_parameters(self): + """Test that create_dm_by_participant_id handles parameters correctly.""" + method = getattr(self.direct_messages_client, "create_dm_by_participant_id") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -716,8 +715,8 @@ def test_create_dm_conversations_required_parameters(self): method() - def test_create_dm_conversations_response_structure(self): - """Test create_dm_conversations response structure validation.""" + def test_create_dm_by_participant_id_response_structure(self): + """Test create_dm_by_participant_id response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -730,13 +729,14 @@ def test_create_dm_conversations_response_structure(self): mock_session.post.return_value = mock_response # Prepare minimal valid parameters kwargs = {} + kwargs["participant_id"] = "test" # Add request body if required # Import and create proper request model instance - from xdk.direct_messages.models import CreateDmConversationsRequest + from xdk.direct_messages.models import CreateDmByParticipantIdRequest # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateDmConversationsRequest() + kwargs["body"] = CreateDmByParticipantIdRequest() # Call method and verify response structure - method = getattr(self.direct_messages_client, "create_dm_conversations") + method = getattr(self.direct_messages_client, "create_dm_by_participant_id") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed diff --git a/xdk/python/tests/direct_messages/test_generic.py b/xdk/python/tests/direct_messages/test_generic.py index 8ac10036..b94f8cf9 100644 --- a/xdk/python/tests/direct_messages/test_generic.py +++ b/xdk/python/tests/direct_messages/test_generic.py @@ -1,5 +1,5 @@ """ -Auto-generated generic tests for Direct_Messages client. +Auto-generated generic tests for {"class_name": "DirectMessages", "display_name": "direct messages", "import_name": "direct_messages", "original": ["direct", "messages"], "property_name": "direct_messages"} client. This module contains general tests that validate the overall client functionality, imports, and error handling that don't need to be diff --git a/xdk/python/tests/direct_messages/test_pagination.py b/xdk/python/tests/direct_messages/test_pagination.py index b6e8322f..bfed914d 100644 --- a/xdk/python/tests/direct_messages/test_pagination.py +++ b/xdk/python/tests/direct_messages/test_pagination.py @@ -1,5 +1,5 @@ """ -Auto-generated pagination tests for Direct_Messages client. +Auto-generated pagination tests for {"class_name": "DirectMessages", "display_name": "direct messages", "import_name": "direct_messages", "original": ["direct", "messages"], "property_name": "direct_messages"} client. This module contains tests that validate pagination functionality using the Cursor class for methods that support pagination. @@ -35,7 +35,7 @@ def test_get_dm_conversations_id_dm_events_cursor_creation(self): assert isinstance(test_cursor, Cursor) except PaginationError: pytest.fail( - f"Method getDmConversationsIdDmEvents should support pagination" + f"Method get_dm_conversations_id_dm_events should support pagination" ) @@ -184,7 +184,9 @@ def test_get_dm_events_by_participant_id_cursor_creation(self): assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method getDmEventsByParticipantId should support pagination") + pytest.fail( + f"Method get_dm_events_by_participant_id should support pagination" + ) def test_get_dm_events_by_participant_id_cursor_pages(self): @@ -323,20 +325,20 @@ def test_get_dm_events_by_participant_id_pagination_parameters(self): ), "Pagination token should be passed correctly" - def test_get_dm_events_cursor_creation(self): - """Test that get_dm_events can be used with Cursor.""" - method = getattr(self.direct_messages_client, "get_dm_events") + def test_get_events_cursor_creation(self): + """Test that get_events can be used with Cursor.""" + method = getattr(self.direct_messages_client, "get_events") # Should be able to create cursor without error try: test_cursor = cursor(method, max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method getDmEvents should support pagination") + pytest.fail(f"Method get_events should support pagination") - def test_get_dm_events_cursor_pages(self): - """Test pagination with pages() for get_dm_events.""" + def test_get_events_cursor_pages(self): + """Test pagination with pages() for get_events.""" with patch.object(self.client, "session") as mock_session: # Mock first page response first_page_response = Mock() @@ -357,7 +359,7 @@ def test_get_dm_events_cursor_pages(self): # Return different responses for consecutive calls mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.direct_messages_client, "get_dm_events") + method = getattr(self.direct_messages_client, "get_events") test_cursor = cursor(method, max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" @@ -373,8 +375,8 @@ def test_get_dm_events_cursor_pages(self): assert len(second_data) == 1, "Second page should have 1 item" - def test_get_dm_events_cursor_items(self): - """Test pagination with items() for get_dm_events.""" + def test_get_events_cursor_items(self): + """Test pagination with items() for get_events.""" with patch.object(self.client, "session") as mock_session: # Mock response with paginated data mock_response = Mock() @@ -393,7 +395,7 @@ def test_get_dm_events_cursor_items(self): mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.direct_messages_client, "get_dm_events") + method = getattr(self.direct_messages_client, "get_events") test_cursor = cursor(method, max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items assert len(items) == 3, f"Should get 3 items, got {len(items)}" @@ -404,15 +406,15 @@ def test_get_dm_events_cursor_items(self): ), "Items should have 'id' field" - def test_get_dm_events_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_dm_events.""" + def test_get_events_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_events.""" with patch.object(self.client, "session") as mock_session: mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.direct_messages_client, "get_dm_events") + method = getattr(self.direct_messages_client, "get_events") # Test with max_results parameter test_cursor = cursor(method, max_results=5) list(test_cursor.pages(1)) # Trigger one request diff --git a/xdk/python/tests/direct_messages/test_structure.py b/xdk/python/tests/direct_messages/test_structure.py index e9ccbcaf..fdc0f06d 100644 --- a/xdk/python/tests/direct_messages/test_structure.py +++ b/xdk/python/tests/direct_messages/test_structure.py @@ -1,8 +1,8 @@ """ -Auto-generated structural tests for Direct_Messages client. +Auto-generated structural tests for {"class_name": "DirectMessages", "display_name": "direct messages", "import_name": "direct_messages", "original": ["direct", "messages"], "property_name": "direct_messages"} client. This module contains tests that validate the structure and API surface -of the Direct_Messages client. These tests ensure that all expected methods +of the {"class_name": "DirectMessages", "display_name": "direct messages", "import_name": "direct_messages", "original": ["direct", "messages"], "property_name": "direct_messages"} client. These tests ensure that all expected methods exist and have the correct signatures. Generated automatically - do not edit manually. @@ -97,39 +97,35 @@ def test_get_dm_conversations_id_dm_events_pagination_params(self): ), f"Paginated method get_dm_conversations_id_dm_events should have pagination parameters" - def test_get_dm_events_by_participant_id_exists(self): - """Test that get_dm_events_by_participant_id method exists with correct signature.""" + def test_create_dm_by_conversation_id_exists(self): + """Test that create_dm_by_conversation_id method exists with correct signature.""" # Check method exists - method = getattr(DirectMessagesClient, "get_dm_events_by_participant_id", None) + method = getattr(DirectMessagesClient, "create_dm_by_conversation_id", None) assert ( method is not None - ), f"Method get_dm_events_by_participant_id does not exist on DirectMessagesClient" + ), f"Method create_dm_by_conversation_id does not exist on DirectMessagesClient" # Check method is callable - assert callable(method), f"get_dm_events_by_participant_id is not callable" + assert callable(method), f"create_dm_by_conversation_id is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"get_dm_events_by_participant_id should have at least 'self' parameter" + ), f"create_dm_by_conversation_id should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "participant_id", + "dm_conversation_id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_dm_events_by_participant_id" + ), f"Required parameter '{required_param}' missing from create_dm_by_conversation_id" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - "event_types", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -138,64 +134,45 @@ def test_get_dm_events_by_participant_id_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_dm_events_by_participant_id_return_annotation(self): - """Test that get_dm_events_by_participant_id has proper return type annotation.""" - method = getattr(DirectMessagesClient, "get_dm_events_by_participant_id") + def test_create_dm_by_conversation_id_return_annotation(self): + """Test that create_dm_by_conversation_id has proper return type annotation.""" + method = getattr(DirectMessagesClient, "create_dm_by_conversation_id") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_dm_events_by_participant_id should have return type annotation" - - - def test_get_dm_events_by_participant_id_pagination_params(self): - """Test that get_dm_events_by_participant_id has pagination parameters.""" - method = getattr(DirectMessagesClient, "get_dm_events_by_participant_id") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_dm_events_by_participant_id should have pagination parameters" + ), f"Method create_dm_by_conversation_id should have return type annotation" - def test_get_dm_events_exists(self): - """Test that get_dm_events method exists with correct signature.""" + def test_get_events_by_id_exists(self): + """Test that get_events_by_id method exists with correct signature.""" # Check method exists - method = getattr(DirectMessagesClient, "get_dm_events", None) + method = getattr(DirectMessagesClient, "get_events_by_id", None) assert ( method is not None - ), f"Method get_dm_events does not exist on DirectMessagesClient" + ), f"Method get_events_by_id does not exist on DirectMessagesClient" # Check method is callable - assert callable(method), f"get_dm_events is not callable" + assert callable(method), f"get_events_by_id is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"get_dm_events should have at least 'self' parameter" + assert ( + len(params) >= 1 + ), f"get_events_by_id should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [] + required_params = [ + "event_id", + ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_dm_events" + ), f"Required parameter '{required_param}' missing from get_events_by_id" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - "event_types", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -204,51 +181,32 @@ def test_get_dm_events_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_dm_events_return_annotation(self): - """Test that get_dm_events has proper return type annotation.""" - method = getattr(DirectMessagesClient, "get_dm_events") + def test_get_events_by_id_return_annotation(self): + """Test that get_events_by_id has proper return type annotation.""" + method = getattr(DirectMessagesClient, "get_events_by_id") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_dm_events should have return type annotation" + ), f"Method get_events_by_id should have return type annotation" - def test_get_dm_events_pagination_params(self): - """Test that get_dm_events has pagination parameters.""" - method = getattr(DirectMessagesClient, "get_dm_events") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_dm_events should have pagination parameters" - - - def test_get_dm_events_by_id_exists(self): - """Test that get_dm_events_by_id method exists with correct signature.""" + def test_delete_dm_events_exists(self): + """Test that delete_dm_events method exists with correct signature.""" # Check method exists - method = getattr(DirectMessagesClient, "get_dm_events_by_id", None) + method = getattr(DirectMessagesClient, "delete_dm_events", None) assert ( method is not None - ), f"Method get_dm_events_by_id does not exist on DirectMessagesClient" + ), f"Method delete_dm_events does not exist on DirectMessagesClient" # Check method is callable - assert callable(method), f"get_dm_events_by_id is not callable" + assert callable(method), f"delete_dm_events is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"get_dm_events_by_id should have at least 'self' parameter" + ), f"delete_dm_events should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -259,7 +217,7 @@ def test_get_dm_events_by_id_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_dm_events_by_id" + ), f"Required parameter '{required_param}' missing from delete_dm_events" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -270,43 +228,41 @@ def test_get_dm_events_by_id_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_dm_events_by_id_return_annotation(self): - """Test that get_dm_events_by_id has proper return type annotation.""" - method = getattr(DirectMessagesClient, "get_dm_events_by_id") + def test_delete_dm_events_return_annotation(self): + """Test that delete_dm_events has proper return type annotation.""" + method = getattr(DirectMessagesClient, "delete_dm_events") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_dm_events_by_id should have return type annotation" + ), f"Method delete_dm_events should have return type annotation" - def test_delete_dm_events_exists(self): - """Test that delete_dm_events method exists with correct signature.""" + def test_create_dm_conversations_exists(self): + """Test that create_dm_conversations method exists with correct signature.""" # Check method exists - method = getattr(DirectMessagesClient, "delete_dm_events", None) + method = getattr(DirectMessagesClient, "create_dm_conversations", None) assert ( method is not None - ), f"Method delete_dm_events does not exist on DirectMessagesClient" + ), f"Method create_dm_conversations does not exist on DirectMessagesClient" # Check method is callable - assert callable(method), f"delete_dm_events is not callable" + assert callable(method), f"create_dm_conversations is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"delete_dm_events should have at least 'self' parameter" + ), f"create_dm_conversations should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [ - "event_id", - ] + required_params = [] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from delete_dm_events" + ), f"Required parameter '{required_param}' missing from create_dm_conversations" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -317,32 +273,32 @@ def test_delete_dm_events_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_delete_dm_events_return_annotation(self): - """Test that delete_dm_events has proper return type annotation.""" - method = getattr(DirectMessagesClient, "delete_dm_events") + def test_create_dm_conversations_return_annotation(self): + """Test that create_dm_conversations has proper return type annotation.""" + method = getattr(DirectMessagesClient, "create_dm_conversations") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method delete_dm_events should have return type annotation" + ), f"Method create_dm_conversations should have return type annotation" - def test_create_dm_by_participant_id_exists(self): - """Test that create_dm_by_participant_id method exists with correct signature.""" + def test_get_dm_events_by_participant_id_exists(self): + """Test that get_dm_events_by_participant_id method exists with correct signature.""" # Check method exists - method = getattr(DirectMessagesClient, "create_dm_by_participant_id", None) + method = getattr(DirectMessagesClient, "get_dm_events_by_participant_id", None) assert ( method is not None - ), f"Method create_dm_by_participant_id does not exist on DirectMessagesClient" + ), f"Method get_dm_events_by_participant_id does not exist on DirectMessagesClient" # Check method is callable - assert callable(method), f"create_dm_by_participant_id is not callable" + assert callable(method), f"get_dm_events_by_participant_id is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"create_dm_by_participant_id should have at least 'self' parameter" + ), f"get_dm_events_by_participant_id should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -353,9 +309,13 @@ def test_create_dm_by_participant_id_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from create_dm_by_participant_id" + ), f"Required parameter '{required_param}' missing from get_dm_events_by_participant_id" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "max_results", + "pagination_token", + "event_types", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -364,45 +324,64 @@ def test_create_dm_by_participant_id_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_create_dm_by_participant_id_return_annotation(self): - """Test that create_dm_by_participant_id has proper return type annotation.""" - method = getattr(DirectMessagesClient, "create_dm_by_participant_id") + def test_get_dm_events_by_participant_id_return_annotation(self): + """Test that get_dm_events_by_participant_id has proper return type annotation.""" + method = getattr(DirectMessagesClient, "get_dm_events_by_participant_id") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method create_dm_by_participant_id should have return type annotation" + ), f"Method get_dm_events_by_participant_id should have return type annotation" - def test_create_dm_by_conversation_id_exists(self): - """Test that create_dm_by_conversation_id method exists with correct signature.""" + def test_get_dm_events_by_participant_id_pagination_params(self): + """Test that get_dm_events_by_participant_id has pagination parameters.""" + method = getattr(DirectMessagesClient, "get_dm_events_by_participant_id") + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have pagination-related parameters + pagination_params = [ + "pagination_token", + "max_results", + "next_token", + "cursor", + "limit", + ] + has_pagination_param = any(param in params for param in pagination_params) + assert ( + has_pagination_param + ), f"Paginated method get_dm_events_by_participant_id should have pagination parameters" + + + def test_get_events_exists(self): + """Test that get_events method exists with correct signature.""" # Check method exists - method = getattr(DirectMessagesClient, "create_dm_by_conversation_id", None) + method = getattr(DirectMessagesClient, "get_events", None) assert ( method is not None - ), f"Method create_dm_by_conversation_id does not exist on DirectMessagesClient" + ), f"Method get_events does not exist on DirectMessagesClient" # Check method is callable - assert callable(method), f"create_dm_by_conversation_id is not callable" + assert callable(method), f"get_events is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"create_dm_by_conversation_id should have at least 'self' parameter" + assert len(params) >= 1, f"get_events should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [ - "dm_conversation_id", - ] + required_params = [] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from create_dm_by_conversation_id" + ), f"Required parameter '{required_param}' missing from get_events" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "max_results", + "pagination_token", + "event_types", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -411,41 +390,62 @@ def test_create_dm_by_conversation_id_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_create_dm_by_conversation_id_return_annotation(self): - """Test that create_dm_by_conversation_id has proper return type annotation.""" - method = getattr(DirectMessagesClient, "create_dm_by_conversation_id") + def test_get_events_return_annotation(self): + """Test that get_events has proper return type annotation.""" + method = getattr(DirectMessagesClient, "get_events") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method create_dm_by_conversation_id should have return type annotation" + ), f"Method get_events should have return type annotation" - def test_create_dm_conversations_exists(self): - """Test that create_dm_conversations method exists with correct signature.""" + def test_get_events_pagination_params(self): + """Test that get_events has pagination parameters.""" + method = getattr(DirectMessagesClient, "get_events") + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have pagination-related parameters + pagination_params = [ + "pagination_token", + "max_results", + "next_token", + "cursor", + "limit", + ] + has_pagination_param = any(param in params for param in pagination_params) + assert ( + has_pagination_param + ), f"Paginated method get_events should have pagination parameters" + + + def test_create_dm_by_participant_id_exists(self): + """Test that create_dm_by_participant_id method exists with correct signature.""" # Check method exists - method = getattr(DirectMessagesClient, "create_dm_conversations", None) + method = getattr(DirectMessagesClient, "create_dm_by_participant_id", None) assert ( method is not None - ), f"Method create_dm_conversations does not exist on DirectMessagesClient" + ), f"Method create_dm_by_participant_id does not exist on DirectMessagesClient" # Check method is callable - assert callable(method), f"create_dm_conversations is not callable" + assert callable(method), f"create_dm_by_participant_id is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"create_dm_conversations should have at least 'self' parameter" + ), f"create_dm_by_participant_id should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [] + required_params = [ + "participant_id", + ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from create_dm_conversations" + ), f"Required parameter '{required_param}' missing from create_dm_by_participant_id" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -456,27 +456,27 @@ def test_create_dm_conversations_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_create_dm_conversations_return_annotation(self): - """Test that create_dm_conversations has proper return type annotation.""" - method = getattr(DirectMessagesClient, "create_dm_conversations") + def test_create_dm_by_participant_id_return_annotation(self): + """Test that create_dm_by_participant_id has proper return type annotation.""" + method = getattr(DirectMessagesClient, "create_dm_by_participant_id") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method create_dm_conversations should have return type annotation" + ), f"Method create_dm_by_participant_id should have return type annotation" def test_all_expected_methods_exist(self): """Test that all expected methods exist on the client.""" expected_methods = [ "get_dm_conversations_id_dm_events", - "get_dm_events_by_participant_id", - "get_dm_events", - "get_dm_events_by_id", - "delete_dm_events", - "create_dm_by_participant_id", "create_dm_by_conversation_id", + "get_events_by_id", + "delete_dm_events", "create_dm_conversations", + "get_dm_events_by_participant_id", + "get_events", + "create_dm_by_participant_id", ] for expected_method in expected_methods: assert hasattr( diff --git a/xdk/python/tests/general/test_contracts.py b/xdk/python/tests/general/test_contracts.py index 88f2bd9a..596d31a1 100644 --- a/xdk/python/tests/general/test_contracts.py +++ b/xdk/python/tests/general/test_contracts.py @@ -1,8 +1,8 @@ """ -Auto-generated contract tests for General client. +Auto-generated contract tests for {"class_name": "General", "display_name": "general", "import_name": "general", "original": ["general"], "property_name": "general"} client. This module contains tests that validate the request/response contracts -of the General client against the OpenAPI specification. +of the {"class_name": "General", "display_name": "general", "import_name": "general", "original": ["general"], "property_name": "general"} client against the OpenAPI specification. Generated automatically - do not edit manually. """ diff --git a/xdk/python/tests/general/test_generic.py b/xdk/python/tests/general/test_generic.py index c4a5f338..1d02585c 100644 --- a/xdk/python/tests/general/test_generic.py +++ b/xdk/python/tests/general/test_generic.py @@ -1,5 +1,5 @@ """ -Auto-generated generic tests for General client. +Auto-generated generic tests for {"class_name": "General", "display_name": "general", "import_name": "general", "original": ["general"], "property_name": "general"} client. This module contains general tests that validate the overall client functionality, imports, and error handling that don't need to be diff --git a/xdk/python/tests/general/test_structure.py b/xdk/python/tests/general/test_structure.py index 3326d274..ad2e1a8c 100644 --- a/xdk/python/tests/general/test_structure.py +++ b/xdk/python/tests/general/test_structure.py @@ -1,8 +1,8 @@ """ -Auto-generated structural tests for General client. +Auto-generated structural tests for {"class_name": "General", "display_name": "general", "import_name": "general", "original": ["general"], "property_name": "general"} client. This module contains tests that validate the structure and API surface -of the General client. These tests ensure that all expected methods +of the {"class_name": "General", "display_name": "general", "import_name": "general", "original": ["general"], "property_name": "general"} client. These tests ensure that all expected methods exist and have the correct signatures. Generated automatically - do not edit manually. diff --git a/xdk/python/tests/likes/__init__.py b/xdk/python/tests/likes/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/tests/likes/test_contracts.py b/xdk/python/tests/likes/test_contracts.py deleted file mode 100644 index 96b079a2..00000000 --- a/xdk/python/tests/likes/test_contracts.py +++ /dev/null @@ -1,194 +0,0 @@ -""" -Auto-generated contract tests for Likes client. - -This module contains tests that validate the request/response contracts -of the Likes client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.likes.client import LikesClient -from xdk import Client - - -class TestLikesContracts: - """Test the API contracts of LikesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.likes_client = getattr(self.client, "likes") - - - def test_stream_likes_firehose_request_structure(self): - """Test stream_likes_firehose request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.likes_client, "stream_likes_firehose") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/likes/firehose/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_likes_firehose: {e}") - - - def test_stream_likes_firehose_required_parameters(self): - """Test that stream_likes_firehose handles parameters correctly.""" - method = getattr(self.likes_client, "stream_likes_firehose") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_likes_firehose_response_structure(self): - """Test stream_likes_firehose response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.likes_client, "stream_likes_firehose") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_likes_sample10_request_structure(self): - """Test stream_likes_sample10 request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.likes_client, "stream_likes_sample10") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/likes/sample10/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_likes_sample10: {e}") - - - def test_stream_likes_sample10_required_parameters(self): - """Test that stream_likes_sample10 handles parameters correctly.""" - method = getattr(self.likes_client, "stream_likes_sample10") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_likes_sample10_response_structure(self): - """Test stream_likes_sample10 response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.likes_client, "stream_likes_sample10") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/tests/likes/test_generic.py b/xdk/python/tests/likes/test_generic.py deleted file mode 100644 index ef2bb285..00000000 --- a/xdk/python/tests/likes/test_generic.py +++ /dev/null @@ -1,122 +0,0 @@ -""" -Auto-generated generic tests for Likes client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.likes.client import LikesClient -from xdk import Client - - -class TestLikesGeneric: - """Generic tests for LikesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.likes_client = getattr(self.client, "likes") - - - def test_client_exists(self): - """Test that LikesClient class exists and is importable.""" - assert LikesClient is not None - assert hasattr(LikesClient, "__name__") - assert LikesClient.__name__ == "LikesClient" - - - def test_client_initialization(self): - """Test that LikesClient can be initialized properly.""" - assert self.likes_client is not None - assert isinstance(self.likes_client, LikesClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(LikesClient) - if not name.startswith("_") and callable(getattr(LikesClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.likes_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "likes") - # Client should have standard Python object features - assert hasattr(self.likes_client, "__class__") - assert hasattr(self.likes_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.likes_client) - if not name.startswith("_") and callable(getattr(self.likes_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"LikesClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(LikesClient) - if not name.startswith("_") and callable(getattr(LikesClient, name)) - ] - for method_name in public_methods: - method = getattr(LikesClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/tests/likes/test_structure.py b/xdk/python/tests/likes/test_structure.py deleted file mode 100644 index 0307474b..00000000 --- a/xdk/python/tests/likes/test_structure.py +++ /dev/null @@ -1,142 +0,0 @@ -""" -Auto-generated structural tests for Likes client. - -This module contains tests that validate the structure and API surface -of the Likes client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.likes.client import LikesClient -from xdk import Client - - -class TestLikesStructure: - """Test the structure of LikesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.likes_client = getattr(self.client, "likes") - - - def test_stream_likes_firehose_exists(self): - """Test that stream_likes_firehose method exists with correct signature.""" - # Check method exists - method = getattr(LikesClient, "stream_likes_firehose", None) - assert ( - method is not None - ), f"Method stream_likes_firehose does not exist on LikesClient" - # Check method is callable - assert callable(method), f"stream_likes_firehose is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_likes_firehose should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_likes_firehose" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_likes_firehose_return_annotation(self): - """Test that stream_likes_firehose has proper return type annotation.""" - method = getattr(LikesClient, "stream_likes_firehose") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_likes_firehose should have return type annotation" - - - def test_stream_likes_sample10_exists(self): - """Test that stream_likes_sample10 method exists with correct signature.""" - # Check method exists - method = getattr(LikesClient, "stream_likes_sample10", None) - assert ( - method is not None - ), f"Method stream_likes_sample10 does not exist on LikesClient" - # Check method is callable - assert callable(method), f"stream_likes_sample10 is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_likes_sample10 should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_likes_sample10" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_likes_sample10_return_annotation(self): - """Test that stream_likes_sample10 has proper return type annotation.""" - method = getattr(LikesClient, "stream_likes_sample10") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_likes_sample10 should have return type annotation" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "stream_likes_firehose", - "stream_likes_sample10", - ] - for expected_method in expected_methods: - assert hasattr( - LikesClient, expected_method - ), f"Expected method '{expected_method}' not found on LikesClient" - assert callable( - getattr(LikesClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/tests/lists/test_contracts.py b/xdk/python/tests/lists/test_contracts.py index 535e9925..1729f41f 100644 --- a/xdk/python/tests/lists/test_contracts.py +++ b/xdk/python/tests/lists/test_contracts.py @@ -1,8 +1,8 @@ """ -Auto-generated contract tests for Lists client. +Auto-generated contract tests for {"class_name": "Lists", "display_name": "lists", "import_name": "lists", "original": ["lists"], "property_name": "lists"} client. This module contains tests that validate the request/response contracts -of the Lists client against the OpenAPI specification. +of the {"class_name": "Lists", "display_name": "lists", "import_name": "lists", "original": ["lists"], "property_name": "lists"} client against the OpenAPI specification. Generated automatically - do not edit manually. """ @@ -24,8 +24,8 @@ def setup_class(self): self.lists_client = getattr(self.client, "lists") - def test_get_users_list_memberships_request_structure(self): - """Test get_users_list_memberships request structure.""" + def test_follow_list_request_structure(self): + """Test follow_list request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -34,25 +34,29 @@ def test_get_users_list_memberships_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters kwargs["id"] = "test_value" # Add request body if required + # Import and create proper request model instance + from xdk.lists.models import FollowListRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = FollowListRequest() # Call the method try: - method = getattr(self.lists_client, "get_users_list_memberships") + method = getattr(self.lists_client, "follow_list") result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.post.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.post.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/list_memberships" + expected_path = "/2/users/{id}/followed_lists" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -61,12 +65,12 @@ def test_get_users_list_memberships_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_list_memberships: {e}") + pytest.fail(f"Contract test failed for follow_list: {e}") - def test_get_users_list_memberships_required_parameters(self): - """Test that get_users_list_memberships handles parameters correctly.""" - method = getattr(self.lists_client, "get_users_list_memberships") + def test_follow_list_required_parameters(self): + """Test that follow_list handles parameters correctly.""" + method = getattr(self.lists_client, "follow_list") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -74,14 +78,14 @@ def test_get_users_list_memberships_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_get_users_list_memberships_response_structure(self): - """Test get_users_list_memberships response structure validation.""" + def test_follow_list_response_structure(self): + """Test follow_list response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -91,13 +95,17 @@ def test_get_users_list_memberships_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" # Add request body if required + # Import and create proper request model instance + from xdk.lists.models import FollowListRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = FollowListRequest() # Call method and verify response structure - method = getattr(self.lists_client, "get_users_list_memberships") + method = getattr(self.lists_client, "follow_list") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -109,8 +117,8 @@ def test_get_users_list_memberships_response_structure(self): ) - def test_get_users_followed_lists_request_structure(self): - """Test get_users_followed_lists request structure.""" + def test_get_by_id_request_structure(self): + """Test get_by_id request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -127,7 +135,7 @@ def test_get_users_followed_lists_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.lists_client, "get_users_followed_lists") + method = getattr(self.lists_client, "get_by_id") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -137,7 +145,7 @@ def test_get_users_followed_lists_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/followed_lists" + expected_path = "/2/lists/{id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -146,12 +154,12 @@ def test_get_users_followed_lists_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_followed_lists: {e}") + pytest.fail(f"Contract test failed for get_by_id: {e}") - def test_get_users_followed_lists_required_parameters(self): - """Test that get_users_followed_lists handles parameters correctly.""" - method = getattr(self.lists_client, "get_users_followed_lists") + def test_get_by_id_required_parameters(self): + """Test that get_by_id handles parameters correctly.""" + method = getattr(self.lists_client, "get_by_id") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -165,8 +173,8 @@ def test_get_users_followed_lists_required_parameters(self): method() - def test_get_users_followed_lists_response_structure(self): - """Test get_users_followed_lists response structure validation.""" + def test_get_by_id_response_structure(self): + """Test get_by_id response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -182,7 +190,7 @@ def test_get_users_followed_lists_response_structure(self): kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.lists_client, "get_users_followed_lists") + method = getattr(self.lists_client, "get_by_id") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -194,8 +202,8 @@ def test_get_users_followed_lists_response_structure(self): ) - def test_follow_list_request_structure(self): - """Test follow_list request structure.""" + def test_update_request_structure(self): + """Test update request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -204,29 +212,29 @@ def test_follow_list_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.put.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters kwargs["id"] = "test_value" # Add request body if required # Import and create proper request model instance - from xdk.lists.models import FollowListRequest + from xdk.lists.models import UpdateRequest # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = FollowListRequest() + kwargs["body"] = UpdateRequest() # Call the method try: - method = getattr(self.lists_client, "follow_list") + method = getattr(self.lists_client, "update") result = method(**kwargs) # Verify the request was made - mock_session.post.assert_called_once() + mock_session.put.assert_called_once() # Verify request structure - call_args = mock_session.post.call_args + call_args = mock_session.put.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/followed_lists" + expected_path = "/2/lists/{id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -235,12 +243,12 @@ def test_follow_list_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for follow_list: {e}") + pytest.fail(f"Contract test failed for update: {e}") - def test_follow_list_required_parameters(self): - """Test that follow_list handles parameters correctly.""" - method = getattr(self.lists_client, "follow_list") + def test_update_required_parameters(self): + """Test that update handles parameters correctly.""" + method = getattr(self.lists_client, "update") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -248,14 +256,14 @@ def test_follow_list_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response + mock_session.put.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_follow_list_response_structure(self): - """Test follow_list response structure validation.""" + def test_update_response_structure(self): + """Test update response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -265,17 +273,17 @@ def test_follow_list_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.put.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" # Add request body if required # Import and create proper request model instance - from xdk.lists.models import FollowListRequest + from xdk.lists.models import UpdateRequest # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = FollowListRequest() + kwargs["body"] = UpdateRequest() # Call method and verify response structure - method = getattr(self.lists_client, "follow_list") + method = getattr(self.lists_client, "update") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -287,8 +295,8 @@ def test_follow_list_response_structure(self): ) - def test_get_lists_by_id_request_structure(self): - """Test get_lists_by_id request structure.""" + def test_delete_request_structure(self): + """Test delete request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -297,7 +305,7 @@ def test_get_lists_by_id_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters @@ -305,12 +313,12 @@ def test_get_lists_by_id_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.lists_client, "get_lists_by_id") + method = getattr(self.lists_client, "delete") result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.delete.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.delete.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") @@ -324,12 +332,12 @@ def test_get_lists_by_id_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_lists_by_id: {e}") + pytest.fail(f"Contract test failed for delete: {e}") - def test_get_lists_by_id_required_parameters(self): - """Test that get_lists_by_id handles parameters correctly.""" - method = getattr(self.lists_client, "get_lists_by_id") + def test_delete_required_parameters(self): + """Test that delete handles parameters correctly.""" + method = getattr(self.lists_client, "delete") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -337,14 +345,14 @@ def test_get_lists_by_id_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_get_lists_by_id_response_structure(self): - """Test get_lists_by_id response structure validation.""" + def test_delete_response_structure(self): + """Test delete response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -354,13 +362,13 @@ def test_get_lists_by_id_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.lists_client, "get_lists_by_id") + method = getattr(self.lists_client, "delete") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -372,8 +380,8 @@ def test_get_lists_by_id_response_structure(self): ) - def test_update_lists_request_structure(self): - """Test update_lists request structure.""" + def test_get_members_request_structure(self): + """Test get_members request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -382,29 +390,25 @@ def test_update_lists_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.put.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters kwargs["id"] = "test_value" # Add request body if required - # Import and create proper request model instance - from xdk.lists.models import UpdateListsRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = UpdateListsRequest() # Call the method try: - method = getattr(self.lists_client, "update_lists") + method = getattr(self.lists_client, "get_members") result = method(**kwargs) # Verify the request was made - mock_session.put.assert_called_once() + mock_session.get.assert_called_once() # Verify request structure - call_args = mock_session.put.call_args + call_args = mock_session.get.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/lists/{id}" + expected_path = "/2/lists/{id}/members" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -413,12 +417,12 @@ def test_update_lists_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for update_lists: {e}") + pytest.fail(f"Contract test failed for get_members: {e}") - def test_update_lists_required_parameters(self): - """Test that update_lists handles parameters correctly.""" - method = getattr(self.lists_client, "update_lists") + def test_get_members_required_parameters(self): + """Test that get_members handles parameters correctly.""" + method = getattr(self.lists_client, "get_members") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -426,14 +430,14 @@ def test_update_lists_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.put.return_value = mock_response + mock_session.get.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_update_lists_response_structure(self): - """Test update_lists response structure validation.""" + def test_get_members_response_structure(self): + """Test get_members response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -443,17 +447,13 @@ def test_update_lists_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.put.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" # Add request body if required - # Import and create proper request model instance - from xdk.lists.models import UpdateListsRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = UpdateListsRequest() # Call method and verify response structure - method = getattr(self.lists_client, "update_lists") + method = getattr(self.lists_client, "get_members") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -465,8 +465,8 @@ def test_update_lists_response_structure(self): ) - def test_delete_lists_request_structure(self): - """Test delete_lists request structure.""" + def test_add_member_request_structure(self): + """Test add_member request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -475,25 +475,29 @@ def test_delete_lists_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters kwargs["id"] = "test_value" # Add request body if required + # Import and create proper request model instance + from xdk.lists.models import AddMemberRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = AddMemberRequest() # Call the method try: - method = getattr(self.lists_client, "delete_lists") + method = getattr(self.lists_client, "add_member") result = method(**kwargs) # Verify the request was made - mock_session.delete.assert_called_once() + mock_session.post.assert_called_once() # Verify request structure - call_args = mock_session.delete.call_args + call_args = mock_session.post.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/lists/{id}" + expected_path = "/2/lists/{id}/members" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -502,12 +506,12 @@ def test_delete_lists_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for delete_lists: {e}") + pytest.fail(f"Contract test failed for add_member: {e}") - def test_delete_lists_required_parameters(self): - """Test that delete_lists handles parameters correctly.""" - method = getattr(self.lists_client, "delete_lists") + def test_add_member_required_parameters(self): + """Test that add_member handles parameters correctly.""" + method = getattr(self.lists_client, "add_member") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -515,14 +519,14 @@ def test_delete_lists_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response + mock_session.post.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_delete_lists_response_structure(self): - """Test delete_lists response structure validation.""" + def test_add_member_response_structure(self): + """Test add_member response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -532,13 +536,17 @@ def test_delete_lists_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" # Add request body if required + # Import and create proper request model instance + from xdk.lists.models import AddMemberRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = AddMemberRequest() # Call method and verify response structure - method = getattr(self.lists_client, "delete_lists") + method = getattr(self.lists_client, "add_member") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -550,8 +558,8 @@ def test_delete_lists_response_structure(self): ) - def test_get_users_pinned_lists_request_structure(self): - """Test get_users_pinned_lists request structure.""" + def test_get_followers_request_structure(self): + """Test get_followers request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -568,7 +576,7 @@ def test_get_users_pinned_lists_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.lists_client, "get_users_pinned_lists") + method = getattr(self.lists_client, "get_followers") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -578,7 +586,7 @@ def test_get_users_pinned_lists_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/pinned_lists" + expected_path = "/2/lists/{id}/followers" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -587,12 +595,12 @@ def test_get_users_pinned_lists_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_pinned_lists: {e}") + pytest.fail(f"Contract test failed for get_followers: {e}") - def test_get_users_pinned_lists_required_parameters(self): - """Test that get_users_pinned_lists handles parameters correctly.""" - method = getattr(self.lists_client, "get_users_pinned_lists") + def test_get_followers_required_parameters(self): + """Test that get_followers handles parameters correctly.""" + method = getattr(self.lists_client, "get_followers") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -606,8 +614,8 @@ def test_get_users_pinned_lists_required_parameters(self): method() - def test_get_users_pinned_lists_response_structure(self): - """Test get_users_pinned_lists response structure validation.""" + def test_get_followers_response_structure(self): + """Test get_followers response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -623,7 +631,7 @@ def test_get_users_pinned_lists_response_structure(self): kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.lists_client, "get_users_pinned_lists") + method = getattr(self.lists_client, "get_followers") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -635,8 +643,8 @@ def test_get_users_pinned_lists_response_structure(self): ) - def test_pin_list_request_structure(self): - """Test pin_list request structure.""" + def test_get_posts_request_structure(self): + """Test get_posts request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -645,29 +653,25 @@ def test_pin_list_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters kwargs["id"] = "test_value" # Add request body if required - # Import and create proper request model instance - from xdk.lists.models import PinListRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = PinListRequest() # Call the method try: - method = getattr(self.lists_client, "pin_list") + method = getattr(self.lists_client, "get_posts") result = method(**kwargs) # Verify the request was made - mock_session.post.assert_called_once() + mock_session.get.assert_called_once() # Verify request structure - call_args = mock_session.post.call_args + call_args = mock_session.get.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/pinned_lists" + expected_path = "/2/lists/{id}/tweets" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -676,12 +680,12 @@ def test_pin_list_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for pin_list: {e}") + pytest.fail(f"Contract test failed for get_posts: {e}") - def test_pin_list_required_parameters(self): - """Test that pin_list handles parameters correctly.""" - method = getattr(self.lists_client, "pin_list") + def test_get_posts_required_parameters(self): + """Test that get_posts handles parameters correctly.""" + method = getattr(self.lists_client, "get_posts") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -689,14 +693,14 @@ def test_pin_list_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_pin_list_response_structure(self): - """Test pin_list response structure validation.""" + def test_get_posts_response_structure(self): + """Test get_posts response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -706,17 +710,13 @@ def test_pin_list_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" # Add request body if required - # Import and create proper request model instance - from xdk.lists.models import PinListRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = PinListRequest() # Call method and verify response structure - method = getattr(self.lists_client, "pin_list") + method = getattr(self.lists_client, "get_posts") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -728,8 +728,8 @@ def test_pin_list_response_structure(self): ) - def test_unpin_list_request_structure(self): - """Test unpin_list request structure.""" + def test_unfollow_list_request_structure(self): + """Test unfollow_list request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -747,7 +747,7 @@ def test_unpin_list_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.lists_client, "unpin_list") + method = getattr(self.lists_client, "unfollow_list") result = method(**kwargs) # Verify the request was made mock_session.delete.assert_called_once() @@ -757,7 +757,7 @@ def test_unpin_list_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/pinned_lists/{list_id}" + expected_path = "/2/users/{id}/followed_lists/{list_id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -766,12 +766,12 @@ def test_unpin_list_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for unpin_list: {e}") + pytest.fail(f"Contract test failed for unfollow_list: {e}") - def test_unpin_list_required_parameters(self): - """Test that unpin_list handles parameters correctly.""" - method = getattr(self.lists_client, "unpin_list") + def test_unfollow_list_required_parameters(self): + """Test that unfollow_list handles parameters correctly.""" + method = getattr(self.lists_client, "unfollow_list") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -785,8 +785,8 @@ def test_unpin_list_required_parameters(self): method() - def test_unpin_list_response_structure(self): - """Test unpin_list response structure validation.""" + def test_unfollow_list_response_structure(self): + """Test unfollow_list response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -803,7 +803,7 @@ def test_unpin_list_response_structure(self): kwargs["list_id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.lists_client, "unpin_list") + method = getattr(self.lists_client, "unfollow_list") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -815,8 +815,8 @@ def test_unpin_list_response_structure(self): ) - def test_remove_lists_member_by_user_id_request_structure(self): - """Test remove_lists_member_by_user_id request structure.""" + def test_get_users_pinned_request_structure(self): + """Test get_users_pinned request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -825,26 +825,25 @@ def test_remove_lists_member_by_user_id_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters kwargs["id"] = "test_value" - kwargs["user_id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.lists_client, "remove_lists_member_by_user_id") + method = getattr(self.lists_client, "get_users_pinned") result = method(**kwargs) # Verify the request was made - mock_session.delete.assert_called_once() + mock_session.get.assert_called_once() # Verify request structure - call_args = mock_session.delete.call_args + call_args = mock_session.get.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/lists/{id}/members/{user_id}" + expected_path = "/2/users/{id}/pinned_lists" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -853,14 +852,12 @@ def test_remove_lists_member_by_user_id_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail( - f"Contract test failed for remove_lists_member_by_user_id: {e}" - ) + pytest.fail(f"Contract test failed for get_users_pinned: {e}") - def test_remove_lists_member_by_user_id_required_parameters(self): - """Test that remove_lists_member_by_user_id handles parameters correctly.""" - method = getattr(self.lists_client, "remove_lists_member_by_user_id") + def test_get_users_pinned_required_parameters(self): + """Test that get_users_pinned handles parameters correctly.""" + method = getattr(self.lists_client, "get_users_pinned") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -868,14 +865,14 @@ def test_remove_lists_member_by_user_id_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response + mock_session.get.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_remove_lists_member_by_user_id_response_structure(self): - """Test remove_lists_member_by_user_id response structure validation.""" + def test_get_users_pinned_response_structure(self): + """Test get_users_pinned response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -885,14 +882,13 @@ def test_remove_lists_member_by_user_id_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" - kwargs["user_id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.lists_client, "remove_lists_member_by_user_id") + method = getattr(self.lists_client, "get_users_pinned") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -904,8 +900,8 @@ def test_remove_lists_member_by_user_id_response_structure(self): ) - def test_get_users_owned_lists_request_structure(self): - """Test get_users_owned_lists request structure.""" + def test_pin_list_request_structure(self): + """Test pin_list request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -914,25 +910,29 @@ def test_get_users_owned_lists_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters kwargs["id"] = "test_value" # Add request body if required + # Import and create proper request model instance + from xdk.lists.models import PinListRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = PinListRequest() # Call the method try: - method = getattr(self.lists_client, "get_users_owned_lists") + method = getattr(self.lists_client, "pin_list") result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.post.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.post.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/owned_lists" + expected_path = "/2/users/{id}/pinned_lists" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -941,12 +941,12 @@ def test_get_users_owned_lists_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_owned_lists: {e}") + pytest.fail(f"Contract test failed for pin_list: {e}") - def test_get_users_owned_lists_required_parameters(self): - """Test that get_users_owned_lists handles parameters correctly.""" - method = getattr(self.lists_client, "get_users_owned_lists") + def test_pin_list_required_parameters(self): + """Test that pin_list handles parameters correctly.""" + method = getattr(self.lists_client, "pin_list") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -954,14 +954,14 @@ def test_get_users_owned_lists_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_get_users_owned_lists_response_structure(self): - """Test get_users_owned_lists response structure validation.""" + def test_pin_list_response_structure(self): + """Test pin_list response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -971,13 +971,17 @@ def test_get_users_owned_lists_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" # Add request body if required + # Import and create proper request model instance + from xdk.lists.models import PinListRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = PinListRequest() # Call method and verify response structure - method = getattr(self.lists_client, "get_users_owned_lists") + method = getattr(self.lists_client, "pin_list") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -989,8 +993,8 @@ def test_get_users_owned_lists_response_structure(self): ) - def test_create_lists_request_structure(self): - """Test create_lists request structure.""" + def test_create_request_structure(self): + """Test create request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1005,12 +1009,12 @@ def test_create_lists_request_structure(self): # Add required parameters # Add request body if required # Import and create proper request model instance - from xdk.lists.models import CreateListsRequest + from xdk.lists.models import CreateRequest # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateListsRequest() + kwargs["body"] = CreateRequest() # Call the method try: - method = getattr(self.lists_client, "create_lists") + method = getattr(self.lists_client, "create") result = method(**kwargs) # Verify the request was made mock_session.post.assert_called_once() @@ -1029,12 +1033,12 @@ def test_create_lists_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for create_lists: {e}") + pytest.fail(f"Contract test failed for create: {e}") - def test_create_lists_required_parameters(self): - """Test that create_lists handles parameters correctly.""" - method = getattr(self.lists_client, "create_lists") + def test_create_required_parameters(self): + """Test that create handles parameters correctly.""" + method = getattr(self.lists_client, "create") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1048,8 +1052,8 @@ def test_create_lists_required_parameters(self): method() - def test_create_lists_response_structure(self): - """Test create_lists response structure validation.""" + def test_create_response_structure(self): + """Test create response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1064,11 +1068,11 @@ def test_create_lists_response_structure(self): kwargs = {} # Add request body if required # Import and create proper request model instance - from xdk.lists.models import CreateListsRequest + from xdk.lists.models import CreateRequest # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateListsRequest() + kwargs["body"] = CreateRequest() # Call method and verify response structure - method = getattr(self.lists_client, "create_lists") + method = getattr(self.lists_client, "create") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1080,8 +1084,8 @@ def test_create_lists_response_structure(self): ) - def test_add_lists_member_request_structure(self): - """Test add_lists_member request structure.""" + def test_remove_member_by_user_id_request_structure(self): + """Test remove_member_by_user_id request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1090,29 +1094,26 @@ def test_add_lists_member_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters kwargs["id"] = "test_value" + kwargs["user_id"] = "test_value" # Add request body if required - # Import and create proper request model instance - from xdk.lists.models import AddListsMemberRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = AddListsMemberRequest() # Call the method try: - method = getattr(self.lists_client, "add_lists_member") + method = getattr(self.lists_client, "remove_member_by_user_id") result = method(**kwargs) # Verify the request was made - mock_session.post.assert_called_once() + mock_session.delete.assert_called_once() # Verify request structure - call_args = mock_session.post.call_args + call_args = mock_session.delete.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/lists/{id}/members" + expected_path = "/2/lists/{id}/members/{user_id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1121,12 +1122,12 @@ def test_add_lists_member_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for add_lists_member: {e}") + pytest.fail(f"Contract test failed for remove_member_by_user_id: {e}") - def test_add_lists_member_required_parameters(self): - """Test that add_lists_member handles parameters correctly.""" - method = getattr(self.lists_client, "add_lists_member") + def test_remove_member_by_user_id_required_parameters(self): + """Test that remove_member_by_user_id handles parameters correctly.""" + method = getattr(self.lists_client, "remove_member_by_user_id") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1134,14 +1135,14 @@ def test_add_lists_member_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response + mock_session.delete.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_add_lists_member_response_structure(self): - """Test add_lists_member response structure validation.""" + def test_remove_member_by_user_id_response_structure(self): + """Test remove_member_by_user_id response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1151,17 +1152,14 @@ def test_add_lists_member_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" + kwargs["user_id"] = "test" # Add request body if required - # Import and create proper request model instance - from xdk.lists.models import AddListsMemberRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = AddListsMemberRequest() # Call method and verify response structure - method = getattr(self.lists_client, "add_lists_member") + method = getattr(self.lists_client, "remove_member_by_user_id") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1173,8 +1171,8 @@ def test_add_lists_member_response_structure(self): ) - def test_unfollow_list_request_structure(self): - """Test unfollow_list request structure.""" + def test_unpin_list_request_structure(self): + """Test unpin_list request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1192,7 +1190,7 @@ def test_unfollow_list_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.lists_client, "unfollow_list") + method = getattr(self.lists_client, "unpin_list") result = method(**kwargs) # Verify the request was made mock_session.delete.assert_called_once() @@ -1202,7 +1200,7 @@ def test_unfollow_list_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/followed_lists/{list_id}" + expected_path = "/2/users/{id}/pinned_lists/{list_id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1211,12 +1209,12 @@ def test_unfollow_list_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for unfollow_list: {e}") + pytest.fail(f"Contract test failed for unpin_list: {e}") - def test_unfollow_list_required_parameters(self): - """Test that unfollow_list handles parameters correctly.""" - method = getattr(self.lists_client, "unfollow_list") + def test_unpin_list_required_parameters(self): + """Test that unpin_list handles parameters correctly.""" + method = getattr(self.lists_client, "unpin_list") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1230,8 +1228,8 @@ def test_unfollow_list_required_parameters(self): method() - def test_unfollow_list_response_structure(self): - """Test unfollow_list response structure validation.""" + def test_unpin_list_response_structure(self): + """Test unpin_list response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1248,7 +1246,7 @@ def test_unfollow_list_response_structure(self): kwargs["list_id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.lists_client, "unfollow_list") + method = getattr(self.lists_client, "unpin_list") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed diff --git a/xdk/python/tests/lists/test_generic.py b/xdk/python/tests/lists/test_generic.py index a964888a..3cbe0952 100644 --- a/xdk/python/tests/lists/test_generic.py +++ b/xdk/python/tests/lists/test_generic.py @@ -1,5 +1,5 @@ """ -Auto-generated generic tests for Lists client. +Auto-generated generic tests for {"class_name": "Lists", "display_name": "lists", "import_name": "lists", "original": ["lists"], "property_name": "lists"} client. This module contains general tests that validate the overall client functionality, imports, and error handling that don't need to be diff --git a/xdk/python/tests/lists/test_pagination.py b/xdk/python/tests/lists/test_pagination.py index 97ee829e..c69ce354 100644 --- a/xdk/python/tests/lists/test_pagination.py +++ b/xdk/python/tests/lists/test_pagination.py @@ -1,5 +1,5 @@ """ -Auto-generated pagination tests for Lists client. +Auto-generated pagination tests for {"class_name": "Lists", "display_name": "lists", "import_name": "lists", "original": ["lists"], "property_name": "lists"} client. This module contains tests that validate pagination functionality using the Cursor class for methods that support pagination. @@ -23,20 +23,20 @@ def setup_class(self): self.lists_client = getattr(self.client, "lists") - def test_get_users_list_memberships_cursor_creation(self): - """Test that get_users_list_memberships can be used with Cursor.""" - method = getattr(self.lists_client, "get_users_list_memberships") + def test_get_members_cursor_creation(self): + """Test that get_members can be used with Cursor.""" + method = getattr(self.lists_client, "get_members") # Should be able to create cursor without error try: test_cursor = cursor(method, "test_id", max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method getUsersListMemberships should support pagination") + pytest.fail(f"Method get_members should support pagination") - def test_get_users_list_memberships_cursor_pages(self): - """Test pagination with pages() for get_users_list_memberships.""" + def test_get_members_cursor_pages(self): + """Test pagination with pages() for get_members.""" with patch.object(self.client, "session") as mock_session: # Mock first page response first_page_response = Mock() @@ -57,7 +57,7 @@ def test_get_users_list_memberships_cursor_pages(self): # Return different responses for consecutive calls mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.lists_client, "get_users_list_memberships") + method = getattr(self.lists_client, "get_members") test_cursor = cursor(method, "test_id", max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" @@ -73,8 +73,8 @@ def test_get_users_list_memberships_cursor_pages(self): assert len(second_data) == 1, "Second page should have 1 item" - def test_get_users_list_memberships_cursor_items(self): - """Test pagination with items() for get_users_list_memberships.""" + def test_get_members_cursor_items(self): + """Test pagination with items() for get_members.""" with patch.object(self.client, "session") as mock_session: # Mock response with paginated data mock_response = Mock() @@ -93,7 +93,7 @@ def test_get_users_list_memberships_cursor_items(self): mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.lists_client, "get_users_list_memberships") + method = getattr(self.lists_client, "get_members") test_cursor = cursor(method, "test_id", max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items assert len(items) == 3, f"Should get 3 items, got {len(items)}" @@ -104,15 +104,15 @@ def test_get_users_list_memberships_cursor_items(self): ), "Items should have 'id' field" - def test_get_users_list_memberships_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_list_memberships.""" + def test_get_members_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_members.""" with patch.object(self.client, "session") as mock_session: mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.lists_client, "get_users_list_memberships") + method = getattr(self.lists_client, "get_members") # Test with max_results parameter test_cursor = cursor(method, "test_id", max_results=5) list(test_cursor.pages(1)) # Trigger one request @@ -165,20 +165,20 @@ def test_get_users_list_memberships_pagination_parameters(self): ), "Pagination token should be passed correctly" - def test_get_users_followed_lists_cursor_creation(self): - """Test that get_users_followed_lists can be used with Cursor.""" - method = getattr(self.lists_client, "get_users_followed_lists") + def test_get_followers_cursor_creation(self): + """Test that get_followers can be used with Cursor.""" + method = getattr(self.lists_client, "get_followers") # Should be able to create cursor without error try: test_cursor = cursor(method, "test_id", max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method getUsersFollowedLists should support pagination") + pytest.fail(f"Method get_followers should support pagination") - def test_get_users_followed_lists_cursor_pages(self): - """Test pagination with pages() for get_users_followed_lists.""" + def test_get_followers_cursor_pages(self): + """Test pagination with pages() for get_followers.""" with patch.object(self.client, "session") as mock_session: # Mock first page response first_page_response = Mock() @@ -199,7 +199,7 @@ def test_get_users_followed_lists_cursor_pages(self): # Return different responses for consecutive calls mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.lists_client, "get_users_followed_lists") + method = getattr(self.lists_client, "get_followers") test_cursor = cursor(method, "test_id", max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" @@ -215,8 +215,8 @@ def test_get_users_followed_lists_cursor_pages(self): assert len(second_data) == 1, "Second page should have 1 item" - def test_get_users_followed_lists_cursor_items(self): - """Test pagination with items() for get_users_followed_lists.""" + def test_get_followers_cursor_items(self): + """Test pagination with items() for get_followers.""" with patch.object(self.client, "session") as mock_session: # Mock response with paginated data mock_response = Mock() @@ -235,7 +235,7 @@ def test_get_users_followed_lists_cursor_items(self): mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.lists_client, "get_users_followed_lists") + method = getattr(self.lists_client, "get_followers") test_cursor = cursor(method, "test_id", max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items assert len(items) == 3, f"Should get 3 items, got {len(items)}" @@ -246,15 +246,15 @@ def test_get_users_followed_lists_cursor_items(self): ), "Items should have 'id' field" - def test_get_users_followed_lists_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_followed_lists.""" + def test_get_followers_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_followers.""" with patch.object(self.client, "session") as mock_session: mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.lists_client, "get_users_followed_lists") + method = getattr(self.lists_client, "get_followers") # Test with max_results parameter test_cursor = cursor(method, "test_id", max_results=5) list(test_cursor.pages(1)) # Trigger one request @@ -307,20 +307,20 @@ def test_get_users_followed_lists_pagination_parameters(self): ), "Pagination token should be passed correctly" - def test_get_users_owned_lists_cursor_creation(self): - """Test that get_users_owned_lists can be used with Cursor.""" - method = getattr(self.lists_client, "get_users_owned_lists") + def test_get_posts_cursor_creation(self): + """Test that get_posts can be used with Cursor.""" + method = getattr(self.lists_client, "get_posts") # Should be able to create cursor without error try: test_cursor = cursor(method, "test_id", max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method getUsersOwnedLists should support pagination") + pytest.fail(f"Method get_posts should support pagination") - def test_get_users_owned_lists_cursor_pages(self): - """Test pagination with pages() for get_users_owned_lists.""" + def test_get_posts_cursor_pages(self): + """Test pagination with pages() for get_posts.""" with patch.object(self.client, "session") as mock_session: # Mock first page response first_page_response = Mock() @@ -341,7 +341,7 @@ def test_get_users_owned_lists_cursor_pages(self): # Return different responses for consecutive calls mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.lists_client, "get_users_owned_lists") + method = getattr(self.lists_client, "get_posts") test_cursor = cursor(method, "test_id", max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" @@ -357,8 +357,8 @@ def test_get_users_owned_lists_cursor_pages(self): assert len(second_data) == 1, "Second page should have 1 item" - def test_get_users_owned_lists_cursor_items(self): - """Test pagination with items() for get_users_owned_lists.""" + def test_get_posts_cursor_items(self): + """Test pagination with items() for get_posts.""" with patch.object(self.client, "session") as mock_session: # Mock response with paginated data mock_response = Mock() @@ -377,7 +377,7 @@ def test_get_users_owned_lists_cursor_items(self): mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.lists_client, "get_users_owned_lists") + method = getattr(self.lists_client, "get_posts") test_cursor = cursor(method, "test_id", max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items assert len(items) == 3, f"Should get 3 items, got {len(items)}" @@ -388,15 +388,15 @@ def test_get_users_owned_lists_cursor_items(self): ), "Items should have 'id' field" - def test_get_users_owned_lists_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_owned_lists.""" + def test_get_posts_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_posts.""" with patch.object(self.client, "session") as mock_session: mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.lists_client, "get_users_owned_lists") + method = getattr(self.lists_client, "get_posts") # Test with max_results parameter test_cursor = cursor(method, "test_id", max_results=5) list(test_cursor.pages(1)) # Trigger one request @@ -459,7 +459,7 @@ def test_pagination_edge_cases(self): empty_response.raise_for_status.return_value = None mock_session.get.return_value = empty_response # Pick first paginatable method for testing - method = getattr(self.lists_client, "get_users_list_memberships") + method = getattr(self.lists_client, "get_members") test_cursor = cursor(method, "test_id", max_results=10) # Should handle empty responses gracefully pages = list(test_cursor.pages(1)) diff --git a/xdk/python/tests/lists/test_structure.py b/xdk/python/tests/lists/test_structure.py index e5744a80..4dbc45f0 100644 --- a/xdk/python/tests/lists/test_structure.py +++ b/xdk/python/tests/lists/test_structure.py @@ -1,8 +1,8 @@ """ -Auto-generated structural tests for Lists client. +Auto-generated structural tests for {"class_name": "Lists", "display_name": "lists", "import_name": "lists", "original": ["lists"], "property_name": "lists"} client. This module contains tests that validate the structure and API surface -of the Lists client. These tests ensure that all expected methods +of the {"class_name": "Lists", "display_name": "lists", "import_name": "lists", "original": ["lists"], "property_name": "lists"} client. These tests ensure that all expected methods exist and have the correct signatures. Generated automatically - do not edit manually. @@ -25,22 +25,18 @@ def setup_class(self): self.lists_client = getattr(self.client, "lists") - def test_get_users_list_memberships_exists(self): - """Test that get_users_list_memberships method exists with correct signature.""" + def test_follow_list_exists(self): + """Test that follow_list method exists with correct signature.""" # Check method exists - method = getattr(ListsClient, "get_users_list_memberships", None) - assert ( - method is not None - ), f"Method get_users_list_memberships does not exist on ListsClient" + method = getattr(ListsClient, "follow_list", None) + assert method is not None, f"Method follow_list does not exist on ListsClient" # Check method is callable - assert callable(method), f"get_users_list_memberships is not callable" + assert callable(method), f"follow_list is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_list_memberships should have at least 'self' parameter" + assert len(params) >= 1, f"follow_list should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -51,12 +47,9 @@ def test_get_users_list_memberships_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_list_memberships" + ), f"Required parameter '{required_param}' missing from follow_list" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -65,51 +58,28 @@ def test_get_users_list_memberships_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_list_memberships_return_annotation(self): - """Test that get_users_list_memberships has proper return type annotation.""" - method = getattr(ListsClient, "get_users_list_memberships") + def test_follow_list_return_annotation(self): + """Test that follow_list has proper return type annotation.""" + method = getattr(ListsClient, "follow_list") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_list_memberships should have return type annotation" - - - def test_get_users_list_memberships_pagination_params(self): - """Test that get_users_list_memberships has pagination parameters.""" - method = getattr(ListsClient, "get_users_list_memberships") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_list_memberships should have pagination parameters" + ), f"Method follow_list should have return type annotation" - def test_get_users_followed_lists_exists(self): - """Test that get_users_followed_lists method exists with correct signature.""" + def test_get_by_id_exists(self): + """Test that get_by_id method exists with correct signature.""" # Check method exists - method = getattr(ListsClient, "get_users_followed_lists", None) - assert ( - method is not None - ), f"Method get_users_followed_lists does not exist on ListsClient" + method = getattr(ListsClient, "get_by_id", None) + assert method is not None, f"Method get_by_id does not exist on ListsClient" # Check method is callable - assert callable(method), f"get_users_followed_lists is not callable" + assert callable(method), f"get_by_id is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_followed_lists should have at least 'self' parameter" + assert len(params) >= 1, f"get_by_id should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -120,12 +90,9 @@ def test_get_users_followed_lists_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_followed_lists" + ), f"Required parameter '{required_param}' missing from get_by_id" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -134,47 +101,28 @@ def test_get_users_followed_lists_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_followed_lists_return_annotation(self): - """Test that get_users_followed_lists has proper return type annotation.""" - method = getattr(ListsClient, "get_users_followed_lists") + def test_get_by_id_return_annotation(self): + """Test that get_by_id has proper return type annotation.""" + method = getattr(ListsClient, "get_by_id") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_followed_lists should have return type annotation" - - - def test_get_users_followed_lists_pagination_params(self): - """Test that get_users_followed_lists has pagination parameters.""" - method = getattr(ListsClient, "get_users_followed_lists") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_followed_lists should have pagination parameters" + ), f"Method get_by_id should have return type annotation" - def test_follow_list_exists(self): - """Test that follow_list method exists with correct signature.""" + def test_update_exists(self): + """Test that update method exists with correct signature.""" # Check method exists - method = getattr(ListsClient, "follow_list", None) - assert method is not None, f"Method follow_list does not exist on ListsClient" + method = getattr(ListsClient, "update", None) + assert method is not None, f"Method update does not exist on ListsClient" # Check method is callable - assert callable(method), f"follow_list is not callable" + assert callable(method), f"update is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"follow_list should have at least 'self' parameter" + assert len(params) >= 1, f"update should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -185,7 +133,7 @@ def test_follow_list_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from follow_list" + ), f"Required parameter '{required_param}' missing from update" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -196,32 +144,28 @@ def test_follow_list_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_follow_list_return_annotation(self): - """Test that follow_list has proper return type annotation.""" - method = getattr(ListsClient, "follow_list") + def test_update_return_annotation(self): + """Test that update has proper return type annotation.""" + method = getattr(ListsClient, "update") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method follow_list should have return type annotation" + ), f"Method update should have return type annotation" - def test_get_lists_by_id_exists(self): - """Test that get_lists_by_id method exists with correct signature.""" + def test_delete_exists(self): + """Test that delete method exists with correct signature.""" # Check method exists - method = getattr(ListsClient, "get_lists_by_id", None) - assert ( - method is not None - ), f"Method get_lists_by_id does not exist on ListsClient" + method = getattr(ListsClient, "delete", None) + assert method is not None, f"Method delete does not exist on ListsClient" # Check method is callable - assert callable(method), f"get_lists_by_id is not callable" + assert callable(method), f"delete is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_lists_by_id should have at least 'self' parameter" + assert len(params) >= 1, f"delete should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -232,7 +176,7 @@ def test_get_lists_by_id_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_lists_by_id" + ), f"Required parameter '{required_param}' missing from delete" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -243,28 +187,28 @@ def test_get_lists_by_id_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_lists_by_id_return_annotation(self): - """Test that get_lists_by_id has proper return type annotation.""" - method = getattr(ListsClient, "get_lists_by_id") + def test_delete_return_annotation(self): + """Test that delete has proper return type annotation.""" + method = getattr(ListsClient, "delete") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_lists_by_id should have return type annotation" + ), f"Method delete should have return type annotation" - def test_update_lists_exists(self): - """Test that update_lists method exists with correct signature.""" + def test_get_members_exists(self): + """Test that get_members method exists with correct signature.""" # Check method exists - method = getattr(ListsClient, "update_lists", None) - assert method is not None, f"Method update_lists does not exist on ListsClient" + method = getattr(ListsClient, "get_members", None) + assert method is not None, f"Method get_members does not exist on ListsClient" # Check method is callable - assert callable(method), f"update_lists is not callable" + assert callable(method), f"get_members is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"update_lists should have at least 'self' parameter" + assert len(params) >= 1, f"get_members should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -275,9 +219,12 @@ def test_update_lists_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from update_lists" + ), f"Required parameter '{required_param}' missing from get_members" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "max_results", + "pagination_token", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -286,28 +233,47 @@ def test_update_lists_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_update_lists_return_annotation(self): - """Test that update_lists has proper return type annotation.""" - method = getattr(ListsClient, "update_lists") + def test_get_members_return_annotation(self): + """Test that get_members has proper return type annotation.""" + method = getattr(ListsClient, "get_members") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method update_lists should have return type annotation" + ), f"Method get_members should have return type annotation" + + + def test_get_members_pagination_params(self): + """Test that get_members has pagination parameters.""" + method = getattr(ListsClient, "get_members") + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have pagination-related parameters + pagination_params = [ + "pagination_token", + "max_results", + "next_token", + "cursor", + "limit", + ] + has_pagination_param = any(param in params for param in pagination_params) + assert ( + has_pagination_param + ), f"Paginated method get_members should have pagination parameters" - def test_delete_lists_exists(self): - """Test that delete_lists method exists with correct signature.""" + def test_add_member_exists(self): + """Test that add_member method exists with correct signature.""" # Check method exists - method = getattr(ListsClient, "delete_lists", None) - assert method is not None, f"Method delete_lists does not exist on ListsClient" + method = getattr(ListsClient, "add_member", None) + assert method is not None, f"Method add_member does not exist on ListsClient" # Check method is callable - assert callable(method), f"delete_lists is not callable" + assert callable(method), f"add_member is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"delete_lists should have at least 'self' parameter" + assert len(params) >= 1, f"add_member should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -318,7 +284,7 @@ def test_delete_lists_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from delete_lists" + ), f"Required parameter '{required_param}' missing from add_member" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -329,32 +295,28 @@ def test_delete_lists_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_delete_lists_return_annotation(self): - """Test that delete_lists has proper return type annotation.""" - method = getattr(ListsClient, "delete_lists") + def test_add_member_return_annotation(self): + """Test that add_member has proper return type annotation.""" + method = getattr(ListsClient, "add_member") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method delete_lists should have return type annotation" + ), f"Method add_member should have return type annotation" - def test_get_users_pinned_lists_exists(self): - """Test that get_users_pinned_lists method exists with correct signature.""" + def test_get_followers_exists(self): + """Test that get_followers method exists with correct signature.""" # Check method exists - method = getattr(ListsClient, "get_users_pinned_lists", None) - assert ( - method is not None - ), f"Method get_users_pinned_lists does not exist on ListsClient" + method = getattr(ListsClient, "get_followers", None) + assert method is not None, f"Method get_followers does not exist on ListsClient" # Check method is callable - assert callable(method), f"get_users_pinned_lists is not callable" + assert callable(method), f"get_followers is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_pinned_lists should have at least 'self' parameter" + assert len(params) >= 1, f"get_followers should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -365,9 +327,12 @@ def test_get_users_pinned_lists_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_pinned_lists" + ), f"Required parameter '{required_param}' missing from get_followers" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "max_results", + "pagination_token", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -376,28 +341,47 @@ def test_get_users_pinned_lists_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_pinned_lists_return_annotation(self): - """Test that get_users_pinned_lists has proper return type annotation.""" - method = getattr(ListsClient, "get_users_pinned_lists") + def test_get_followers_return_annotation(self): + """Test that get_followers has proper return type annotation.""" + method = getattr(ListsClient, "get_followers") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_pinned_lists should have return type annotation" + ), f"Method get_followers should have return type annotation" - def test_pin_list_exists(self): - """Test that pin_list method exists with correct signature.""" + def test_get_followers_pagination_params(self): + """Test that get_followers has pagination parameters.""" + method = getattr(ListsClient, "get_followers") + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have pagination-related parameters + pagination_params = [ + "pagination_token", + "max_results", + "next_token", + "cursor", + "limit", + ] + has_pagination_param = any(param in params for param in pagination_params) + assert ( + has_pagination_param + ), f"Paginated method get_followers should have pagination parameters" + + + def test_get_posts_exists(self): + """Test that get_posts method exists with correct signature.""" # Check method exists - method = getattr(ListsClient, "pin_list", None) - assert method is not None, f"Method pin_list does not exist on ListsClient" + method = getattr(ListsClient, "get_posts", None) + assert method is not None, f"Method get_posts does not exist on ListsClient" # Check method is callable - assert callable(method), f"pin_list is not callable" + assert callable(method), f"get_posts is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"pin_list should have at least 'self' parameter" + assert len(params) >= 1, f"get_posts should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -408,9 +392,12 @@ def test_pin_list_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from pin_list" + ), f"Required parameter '{required_param}' missing from get_posts" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "max_results", + "pagination_token", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -419,28 +406,47 @@ def test_pin_list_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_pin_list_return_annotation(self): - """Test that pin_list has proper return type annotation.""" - method = getattr(ListsClient, "pin_list") + def test_get_posts_return_annotation(self): + """Test that get_posts has proper return type annotation.""" + method = getattr(ListsClient, "get_posts") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method pin_list should have return type annotation" + ), f"Method get_posts should have return type annotation" - def test_unpin_list_exists(self): - """Test that unpin_list method exists with correct signature.""" + def test_get_posts_pagination_params(self): + """Test that get_posts has pagination parameters.""" + method = getattr(ListsClient, "get_posts") + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have pagination-related parameters + pagination_params = [ + "pagination_token", + "max_results", + "next_token", + "cursor", + "limit", + ] + has_pagination_param = any(param in params for param in pagination_params) + assert ( + has_pagination_param + ), f"Paginated method get_posts should have pagination parameters" + + + def test_unfollow_list_exists(self): + """Test that unfollow_list method exists with correct signature.""" # Check method exists - method = getattr(ListsClient, "unpin_list", None) - assert method is not None, f"Method unpin_list does not exist on ListsClient" + method = getattr(ListsClient, "unfollow_list", None) + assert method is not None, f"Method unfollow_list does not exist on ListsClient" # Check method is callable - assert callable(method), f"unpin_list is not callable" + assert callable(method), f"unfollow_list is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"unpin_list should have at least 'self' parameter" + assert len(params) >= 1, f"unfollow_list should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -452,7 +458,7 @@ def test_unpin_list_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from unpin_list" + ), f"Required parameter '{required_param}' missing from unfollow_list" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -463,44 +469,43 @@ def test_unpin_list_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_unpin_list_return_annotation(self): - """Test that unpin_list has proper return type annotation.""" - method = getattr(ListsClient, "unpin_list") + def test_unfollow_list_return_annotation(self): + """Test that unfollow_list has proper return type annotation.""" + method = getattr(ListsClient, "unfollow_list") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method unpin_list should have return type annotation" + ), f"Method unfollow_list should have return type annotation" - def test_remove_lists_member_by_user_id_exists(self): - """Test that remove_lists_member_by_user_id method exists with correct signature.""" + def test_get_users_pinned_exists(self): + """Test that get_users_pinned method exists with correct signature.""" # Check method exists - method = getattr(ListsClient, "remove_lists_member_by_user_id", None) + method = getattr(ListsClient, "get_users_pinned", None) assert ( method is not None - ), f"Method remove_lists_member_by_user_id does not exist on ListsClient" + ), f"Method get_users_pinned does not exist on ListsClient" # Check method is callable - assert callable(method), f"remove_lists_member_by_user_id is not callable" + assert callable(method), f"get_users_pinned is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"remove_lists_member_by_user_id should have at least 'self' parameter" + ), f"get_users_pinned should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ "id", - "user_id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from remove_lists_member_by_user_id" + ), f"Required parameter '{required_param}' missing from get_users_pinned" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -511,32 +516,28 @@ def test_remove_lists_member_by_user_id_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_remove_lists_member_by_user_id_return_annotation(self): - """Test that remove_lists_member_by_user_id has proper return type annotation.""" - method = getattr(ListsClient, "remove_lists_member_by_user_id") + def test_get_users_pinned_return_annotation(self): + """Test that get_users_pinned has proper return type annotation.""" + method = getattr(ListsClient, "get_users_pinned") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method remove_lists_member_by_user_id should have return type annotation" + ), f"Method get_users_pinned should have return type annotation" - def test_get_users_owned_lists_exists(self): - """Test that get_users_owned_lists method exists with correct signature.""" + def test_pin_list_exists(self): + """Test that pin_list method exists with correct signature.""" # Check method exists - method = getattr(ListsClient, "get_users_owned_lists", None) - assert ( - method is not None - ), f"Method get_users_owned_lists does not exist on ListsClient" + method = getattr(ListsClient, "pin_list", None) + assert method is not None, f"Method pin_list does not exist on ListsClient" # Check method is callable - assert callable(method), f"get_users_owned_lists is not callable" + assert callable(method), f"pin_list is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_owned_lists should have at least 'self' parameter" + assert len(params) >= 1, f"pin_list should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -547,12 +548,9 @@ def test_get_users_owned_lists_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_owned_lists" + ), f"Required parameter '{required_param}' missing from pin_list" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -561,47 +559,28 @@ def test_get_users_owned_lists_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_owned_lists_return_annotation(self): - """Test that get_users_owned_lists has proper return type annotation.""" - method = getattr(ListsClient, "get_users_owned_lists") + def test_pin_list_return_annotation(self): + """Test that pin_list has proper return type annotation.""" + method = getattr(ListsClient, "pin_list") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_owned_lists should have return type annotation" - - - def test_get_users_owned_lists_pagination_params(self): - """Test that get_users_owned_lists has pagination parameters.""" - method = getattr(ListsClient, "get_users_owned_lists") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_owned_lists should have pagination parameters" + ), f"Method pin_list should have return type annotation" - def test_create_lists_exists(self): - """Test that create_lists method exists with correct signature.""" + def test_create_exists(self): + """Test that create method exists with correct signature.""" # Check method exists - method = getattr(ListsClient, "create_lists", None) - assert method is not None, f"Method create_lists does not exist on ListsClient" + method = getattr(ListsClient, "create", None) + assert method is not None, f"Method create does not exist on ListsClient" # Check method is callable - assert callable(method), f"create_lists is not callable" + assert callable(method), f"create is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"create_lists should have at least 'self' parameter" + assert len(params) >= 1, f"create should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -610,7 +589,7 @@ def test_create_lists_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from create_lists" + ), f"Required parameter '{required_param}' missing from create" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -621,43 +600,44 @@ def test_create_lists_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_create_lists_return_annotation(self): - """Test that create_lists has proper return type annotation.""" - method = getattr(ListsClient, "create_lists") + def test_create_return_annotation(self): + """Test that create has proper return type annotation.""" + method = getattr(ListsClient, "create") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method create_lists should have return type annotation" + ), f"Method create should have return type annotation" - def test_add_lists_member_exists(self): - """Test that add_lists_member method exists with correct signature.""" + def test_remove_member_by_user_id_exists(self): + """Test that remove_member_by_user_id method exists with correct signature.""" # Check method exists - method = getattr(ListsClient, "add_lists_member", None) + method = getattr(ListsClient, "remove_member_by_user_id", None) assert ( method is not None - ), f"Method add_lists_member does not exist on ListsClient" + ), f"Method remove_member_by_user_id does not exist on ListsClient" # Check method is callable - assert callable(method), f"add_lists_member is not callable" + assert callable(method), f"remove_member_by_user_id is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"add_lists_member should have at least 'self' parameter" + ), f"remove_member_by_user_id should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ "id", + "user_id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from add_lists_member" + ), f"Required parameter '{required_param}' missing from remove_member_by_user_id" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -668,28 +648,28 @@ def test_add_lists_member_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_add_lists_member_return_annotation(self): - """Test that add_lists_member has proper return type annotation.""" - method = getattr(ListsClient, "add_lists_member") + def test_remove_member_by_user_id_return_annotation(self): + """Test that remove_member_by_user_id has proper return type annotation.""" + method = getattr(ListsClient, "remove_member_by_user_id") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method add_lists_member should have return type annotation" + ), f"Method remove_member_by_user_id should have return type annotation" - def test_unfollow_list_exists(self): - """Test that unfollow_list method exists with correct signature.""" + def test_unpin_list_exists(self): + """Test that unpin_list method exists with correct signature.""" # Check method exists - method = getattr(ListsClient, "unfollow_list", None) - assert method is not None, f"Method unfollow_list does not exist on ListsClient" + method = getattr(ListsClient, "unpin_list", None) + assert method is not None, f"Method unpin_list does not exist on ListsClient" # Check method is callable - assert callable(method), f"unfollow_list is not callable" + assert callable(method), f"unpin_list is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"unfollow_list should have at least 'self' parameter" + assert len(params) >= 1, f"unpin_list should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -701,7 +681,7 @@ def test_unfollow_list_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from unfollow_list" + ), f"Required parameter '{required_param}' missing from unpin_list" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -712,33 +692,33 @@ def test_unfollow_list_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_unfollow_list_return_annotation(self): - """Test that unfollow_list has proper return type annotation.""" - method = getattr(ListsClient, "unfollow_list") + def test_unpin_list_return_annotation(self): + """Test that unpin_list has proper return type annotation.""" + method = getattr(ListsClient, "unpin_list") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method unfollow_list should have return type annotation" + ), f"Method unpin_list should have return type annotation" def test_all_expected_methods_exist(self): """Test that all expected methods exist on the client.""" expected_methods = [ - "get_users_list_memberships", - "get_users_followed_lists", "follow_list", - "get_lists_by_id", - "update_lists", - "delete_lists", - "get_users_pinned_lists", + "get_by_id", + "update", + "delete", + "get_members", + "add_member", + "get_followers", + "get_posts", + "unfollow_list", + "get_users_pinned", "pin_list", + "create", + "remove_member_by_user_id", "unpin_list", - "remove_lists_member_by_user_id", - "get_users_owned_lists", - "create_lists", - "add_lists_member", - "unfollow_list", ] for expected_method in expected_methods: assert hasattr( diff --git a/xdk/python/tests/media/test_contracts.py b/xdk/python/tests/media/test_contracts.py index 687493d5..df147a30 100644 --- a/xdk/python/tests/media/test_contracts.py +++ b/xdk/python/tests/media/test_contracts.py @@ -1,8 +1,8 @@ """ -Auto-generated contract tests for Media client. +Auto-generated contract tests for {"class_name": "Media", "display_name": "media", "import_name": "media", "original": ["media"], "property_name": "media"} client. This module contains tests that validate the request/response contracts -of the Media client against the OpenAPI specification. +of the {"class_name": "Media", "display_name": "media", "import_name": "media", "original": ["media"], "property_name": "media"} client against the OpenAPI specification. Generated automatically - do not edit manually. """ @@ -24,8 +24,8 @@ def setup_class(self): self.media_client = getattr(self.client, "media") - def test_create_media_metadata_request_structure(self): - """Test create_media_metadata request structure.""" + def test_initialize_upload_request_structure(self): + """Test initialize_upload request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -40,12 +40,12 @@ def test_create_media_metadata_request_structure(self): # Add required parameters # Add request body if required # Import and create proper request model instance - from xdk.media.models import CreateMediaMetadataRequest + from xdk.media.models import InitializeUploadRequest # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateMediaMetadataRequest() + kwargs["body"] = InitializeUploadRequest() # Call the method try: - method = getattr(self.media_client, "create_media_metadata") + method = getattr(self.media_client, "initialize_upload") result = method(**kwargs) # Verify the request was made mock_session.post.assert_called_once() @@ -55,7 +55,7 @@ def test_create_media_metadata_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/media/metadata" + expected_path = "/2/media/upload/initialize" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -64,12 +64,12 @@ def test_create_media_metadata_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for create_media_metadata: {e}") + pytest.fail(f"Contract test failed for initialize_upload: {e}") - def test_create_media_metadata_required_parameters(self): - """Test that create_media_metadata handles parameters correctly.""" - method = getattr(self.media_client, "create_media_metadata") + def test_initialize_upload_required_parameters(self): + """Test that initialize_upload handles parameters correctly.""" + method = getattr(self.media_client, "initialize_upload") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -83,8 +83,8 @@ def test_create_media_metadata_required_parameters(self): method() - def test_create_media_metadata_response_structure(self): - """Test create_media_metadata response structure validation.""" + def test_initialize_upload_response_structure(self): + """Test initialize_upload response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -99,11 +99,11 @@ def test_create_media_metadata_response_structure(self): kwargs = {} # Add request body if required # Import and create proper request model instance - from xdk.media.models import CreateMediaMetadataRequest + from xdk.media.models import InitializeUploadRequest # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateMediaMetadataRequest() + kwargs["body"] = InitializeUploadRequest() # Call method and verify response structure - method = getattr(self.media_client, "create_media_metadata") + method = getattr(self.media_client, "initialize_upload") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -115,8 +115,8 @@ def test_create_media_metadata_response_structure(self): ) - def test_create_media_subtitles_request_structure(self): - """Test create_media_subtitles request structure.""" + def test_create_subtitles_request_structure(self): + """Test create_subtitles request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -131,12 +131,12 @@ def test_create_media_subtitles_request_structure(self): # Add required parameters # Add request body if required # Import and create proper request model instance - from xdk.media.models import CreateMediaSubtitlesRequest + from xdk.media.models import CreateSubtitlesRequest # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateMediaSubtitlesRequest() + kwargs["body"] = CreateSubtitlesRequest() # Call the method try: - method = getattr(self.media_client, "create_media_subtitles") + method = getattr(self.media_client, "create_subtitles") result = method(**kwargs) # Verify the request was made mock_session.post.assert_called_once() @@ -155,12 +155,12 @@ def test_create_media_subtitles_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for create_media_subtitles: {e}") + pytest.fail(f"Contract test failed for create_subtitles: {e}") - def test_create_media_subtitles_required_parameters(self): - """Test that create_media_subtitles handles parameters correctly.""" - method = getattr(self.media_client, "create_media_subtitles") + def test_create_subtitles_required_parameters(self): + """Test that create_subtitles handles parameters correctly.""" + method = getattr(self.media_client, "create_subtitles") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -174,8 +174,8 @@ def test_create_media_subtitles_required_parameters(self): method() - def test_create_media_subtitles_response_structure(self): - """Test create_media_subtitles response structure validation.""" + def test_create_subtitles_response_structure(self): + """Test create_subtitles response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -190,11 +190,11 @@ def test_create_media_subtitles_response_structure(self): kwargs = {} # Add request body if required # Import and create proper request model instance - from xdk.media.models import CreateMediaSubtitlesRequest + from xdk.media.models import CreateSubtitlesRequest # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateMediaSubtitlesRequest() + kwargs["body"] = CreateSubtitlesRequest() # Call method and verify response structure - method = getattr(self.media_client, "create_media_subtitles") + method = getattr(self.media_client, "create_subtitles") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -206,8 +206,8 @@ def test_create_media_subtitles_response_structure(self): ) - def test_delete_media_subtitles_request_structure(self): - """Test delete_media_subtitles request structure.""" + def test_delete_subtitles_request_structure(self): + """Test delete_subtitles request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -222,12 +222,12 @@ def test_delete_media_subtitles_request_structure(self): # Add required parameters # Add request body if required # Import and create proper request model instance - from xdk.media.models import DeleteMediaSubtitlesRequest + from xdk.media.models import DeleteSubtitlesRequest # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = DeleteMediaSubtitlesRequest() + kwargs["body"] = DeleteSubtitlesRequest() # Call the method try: - method = getattr(self.media_client, "delete_media_subtitles") + method = getattr(self.media_client, "delete_subtitles") result = method(**kwargs) # Verify the request was made mock_session.delete.assert_called_once() @@ -246,12 +246,12 @@ def test_delete_media_subtitles_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for delete_media_subtitles: {e}") + pytest.fail(f"Contract test failed for delete_subtitles: {e}") - def test_delete_media_subtitles_required_parameters(self): - """Test that delete_media_subtitles handles parameters correctly.""" - method = getattr(self.media_client, "delete_media_subtitles") + def test_delete_subtitles_required_parameters(self): + """Test that delete_subtitles handles parameters correctly.""" + method = getattr(self.media_client, "delete_subtitles") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -265,8 +265,8 @@ def test_delete_media_subtitles_required_parameters(self): method() - def test_delete_media_subtitles_response_structure(self): - """Test delete_media_subtitles response structure validation.""" + def test_delete_subtitles_response_structure(self): + """Test delete_subtitles response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -281,11 +281,11 @@ def test_delete_media_subtitles_response_structure(self): kwargs = {} # Add request body if required # Import and create proper request model instance - from xdk.media.models import DeleteMediaSubtitlesRequest + from xdk.media.models import DeleteSubtitlesRequest # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = DeleteMediaSubtitlesRequest() + kwargs["body"] = DeleteSubtitlesRequest() # Call method and verify response structure - method = getattr(self.media_client, "delete_media_subtitles") + method = getattr(self.media_client, "delete_subtitles") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -297,8 +297,8 @@ def test_delete_media_subtitles_response_structure(self): ) - def test_get_media_upload_status_request_structure(self): - """Test get_media_upload_status request structure.""" + def test_append_upload_request_structure(self): + """Test append_upload request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -307,25 +307,29 @@ def test_get_media_upload_status_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["media_id"] = "test_value" + kwargs["id"] = "test_value" # Add request body if required + # Import and create proper request model instance + from xdk.media.models import AppendUploadRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = AppendUploadRequest() # Call the method try: - method = getattr(self.media_client, "get_media_upload_status") + method = getattr(self.media_client, "append_upload") result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.post.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.post.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/media/upload" + expected_path = "/2/media/upload/{id}/append" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -334,12 +338,12 @@ def test_get_media_upload_status_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_media_upload_status: {e}") + pytest.fail(f"Contract test failed for append_upload: {e}") - def test_get_media_upload_status_required_parameters(self): - """Test that get_media_upload_status handles parameters correctly.""" - method = getattr(self.media_client, "get_media_upload_status") + def test_append_upload_required_parameters(self): + """Test that append_upload handles parameters correctly.""" + method = getattr(self.media_client, "append_upload") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -347,14 +351,14 @@ def test_get_media_upload_status_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_get_media_upload_status_response_structure(self): - """Test get_media_upload_status response structure validation.""" + def test_append_upload_response_structure(self): + """Test append_upload response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -364,13 +368,17 @@ def test_get_media_upload_status_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["media_id"] = "test" + kwargs["id"] = "test" # Add request body if required + # Import and create proper request model instance + from xdk.media.models import AppendUploadRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = AppendUploadRequest() # Call method and verify response structure - method = getattr(self.media_client, "get_media_upload_status") + method = getattr(self.media_client, "append_upload") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -382,8 +390,8 @@ def test_get_media_upload_status_response_structure(self): ) - def test_media_upload_request_structure(self): - """Test media_upload request structure.""" + def test_get_upload_status_request_structure(self): + """Test get_upload_status request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -392,23 +400,20 @@ def test_media_upload_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters + kwargs["media_id"] = "test_value" # Add request body if required - # Import and create proper request model instance - from xdk.media.models import MediaUploadRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = MediaUploadRequest() # Call the method try: - method = getattr(self.media_client, "media_upload") + method = getattr(self.media_client, "get_upload_status") result = method(**kwargs) # Verify the request was made - mock_session.post.assert_called_once() + mock_session.get.assert_called_once() # Verify request structure - call_args = mock_session.post.call_args + call_args = mock_session.get.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") @@ -422,12 +427,12 @@ def test_media_upload_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for media_upload: {e}") + pytest.fail(f"Contract test failed for get_upload_status: {e}") - def test_media_upload_required_parameters(self): - """Test that media_upload handles parameters correctly.""" - method = getattr(self.media_client, "media_upload") + def test_get_upload_status_required_parameters(self): + """Test that get_upload_status handles parameters correctly.""" + method = getattr(self.media_client, "get_upload_status") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -435,14 +440,14 @@ def test_media_upload_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_media_upload_response_structure(self): - """Test media_upload response structure validation.""" + def test_get_upload_status_response_structure(self): + """Test get_upload_status response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -452,16 +457,13 @@ def test_media_upload_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} + kwargs["media_id"] = "test" # Add request body if required - # Import and create proper request model instance - from xdk.media.models import MediaUploadRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = MediaUploadRequest() # Call method and verify response structure - method = getattr(self.media_client, "media_upload") + method = getattr(self.media_client, "get_upload_status") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -473,8 +475,8 @@ def test_media_upload_response_structure(self): ) - def test_initialize_media_upload_request_structure(self): - """Test initialize_media_upload request structure.""" + def test_upload_request_structure(self): + """Test upload request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -489,12 +491,12 @@ def test_initialize_media_upload_request_structure(self): # Add required parameters # Add request body if required # Import and create proper request model instance - from xdk.media.models import InitializeMediaUploadRequest + from xdk.media.models import UploadRequest # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = InitializeMediaUploadRequest() + kwargs["body"] = UploadRequest() # Call the method try: - method = getattr(self.media_client, "initialize_media_upload") + method = getattr(self.media_client, "upload") result = method(**kwargs) # Verify the request was made mock_session.post.assert_called_once() @@ -504,7 +506,7 @@ def test_initialize_media_upload_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/media/upload/initialize" + expected_path = "/2/media/upload" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -513,12 +515,12 @@ def test_initialize_media_upload_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for initialize_media_upload: {e}") + pytest.fail(f"Contract test failed for upload: {e}") - def test_initialize_media_upload_required_parameters(self): - """Test that initialize_media_upload handles parameters correctly.""" - method = getattr(self.media_client, "initialize_media_upload") + def test_upload_required_parameters(self): + """Test that upload handles parameters correctly.""" + method = getattr(self.media_client, "upload") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -532,8 +534,8 @@ def test_initialize_media_upload_required_parameters(self): method() - def test_initialize_media_upload_response_structure(self): - """Test initialize_media_upload response structure validation.""" + def test_upload_response_structure(self): + """Test upload response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -548,11 +550,11 @@ def test_initialize_media_upload_response_structure(self): kwargs = {} # Add request body if required # Import and create proper request model instance - from xdk.media.models import InitializeMediaUploadRequest + from xdk.media.models import UploadRequest # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = InitializeMediaUploadRequest() + kwargs["body"] = UploadRequest() # Call method and verify response structure - method = getattr(self.media_client, "initialize_media_upload") + method = getattr(self.media_client, "upload") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -564,8 +566,8 @@ def test_initialize_media_upload_response_structure(self): ) - def test_get_media_analytics_request_structure(self): - """Test get_media_analytics request structure.""" + def test_finalize_upload_request_structure(self): + """Test finalize_upload request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -574,28 +576,25 @@ def test_get_media_analytics_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["media_keys"] = ["test_item"] - kwargs["end_time"] = "test_end_time" - kwargs["start_time"] = "test_start_time" - kwargs["granularity"] = "test_granularity" + kwargs["id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.media_client, "get_media_analytics") + method = getattr(self.media_client, "finalize_upload") result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.post.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.post.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/media/analytics" + expected_path = "/2/media/upload/{id}/finalize" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -604,12 +603,12 @@ def test_get_media_analytics_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_media_analytics: {e}") + pytest.fail(f"Contract test failed for finalize_upload: {e}") - def test_get_media_analytics_required_parameters(self): - """Test that get_media_analytics handles parameters correctly.""" - method = getattr(self.media_client, "get_media_analytics") + def test_finalize_upload_required_parameters(self): + """Test that finalize_upload handles parameters correctly.""" + method = getattr(self.media_client, "finalize_upload") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -617,14 +616,14 @@ def test_get_media_analytics_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_get_media_analytics_response_structure(self): - """Test get_media_analytics response structure validation.""" + def test_finalize_upload_response_structure(self): + """Test finalize_upload response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -634,16 +633,13 @@ def test_get_media_analytics_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["media_keys"] = ["test"] - kwargs["end_time"] = "test_value" - kwargs["start_time"] = "test_value" - kwargs["granularity"] = "test_value" + kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.media_client, "get_media_analytics") + method = getattr(self.media_client, "finalize_upload") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -655,8 +651,8 @@ def test_get_media_analytics_response_structure(self): ) - def test_get_media_by_media_keys_request_structure(self): - """Test get_media_by_media_keys request structure.""" + def test_get_analytics_request_structure(self): + """Test get_analytics request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -670,10 +666,13 @@ def test_get_media_by_media_keys_request_structure(self): kwargs = {} # Add required parameters kwargs["media_keys"] = ["test_item"] + kwargs["end_time"] = "test_end_time" + kwargs["start_time"] = "test_start_time" + kwargs["granularity"] = "test_granularity" # Add request body if required # Call the method try: - method = getattr(self.media_client, "get_media_by_media_keys") + method = getattr(self.media_client, "get_analytics") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -683,7 +682,7 @@ def test_get_media_by_media_keys_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/media" + expected_path = "/2/media/analytics" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -692,12 +691,12 @@ def test_get_media_by_media_keys_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_media_by_media_keys: {e}") + pytest.fail(f"Contract test failed for get_analytics: {e}") - def test_get_media_by_media_keys_required_parameters(self): - """Test that get_media_by_media_keys handles parameters correctly.""" - method = getattr(self.media_client, "get_media_by_media_keys") + def test_get_analytics_required_parameters(self): + """Test that get_analytics handles parameters correctly.""" + method = getattr(self.media_client, "get_analytics") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -711,8 +710,8 @@ def test_get_media_by_media_keys_required_parameters(self): method() - def test_get_media_by_media_keys_response_structure(self): - """Test get_media_by_media_keys response structure validation.""" + def test_get_analytics_response_structure(self): + """Test get_analytics response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -726,9 +725,12 @@ def test_get_media_by_media_keys_response_structure(self): # Prepare minimal valid parameters kwargs = {} kwargs["media_keys"] = ["test"] + kwargs["end_time"] = "test_value" + kwargs["start_time"] = "test_value" + kwargs["granularity"] = "test_value" # Add request body if required # Call method and verify response structure - method = getattr(self.media_client, "get_media_by_media_keys") + method = getattr(self.media_client, "get_analytics") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -740,8 +742,8 @@ def test_get_media_by_media_keys_response_structure(self): ) - def test_get_media_by_media_key_request_structure(self): - """Test get_media_by_media_key request structure.""" + def test_get_by_key_request_structure(self): + """Test get_by_key request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -758,7 +760,7 @@ def test_get_media_by_media_key_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.media_client, "get_media_by_media_key") + method = getattr(self.media_client, "get_by_key") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -777,12 +779,12 @@ def test_get_media_by_media_key_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_media_by_media_key: {e}") + pytest.fail(f"Contract test failed for get_by_key: {e}") - def test_get_media_by_media_key_required_parameters(self): - """Test that get_media_by_media_key handles parameters correctly.""" - method = getattr(self.media_client, "get_media_by_media_key") + def test_get_by_key_required_parameters(self): + """Test that get_by_key handles parameters correctly.""" + method = getattr(self.media_client, "get_by_key") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -796,8 +798,8 @@ def test_get_media_by_media_key_required_parameters(self): method() - def test_get_media_by_media_key_response_structure(self): - """Test get_media_by_media_key response structure validation.""" + def test_get_by_key_response_structure(self): + """Test get_by_key response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -813,7 +815,7 @@ def test_get_media_by_media_key_response_structure(self): kwargs["media_key"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.media_client, "get_media_by_media_key") + method = getattr(self.media_client, "get_by_key") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -825,8 +827,8 @@ def test_get_media_by_media_key_response_structure(self): ) - def test_finalize_media_upload_request_structure(self): - """Test finalize_media_upload request structure.""" + def test_create_metadata_request_structure(self): + """Test create_metadata request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -839,11 +841,14 @@ def test_finalize_media_upload_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["id"] = "test_value" # Add request body if required + # Import and create proper request model instance + from xdk.media.models import CreateMetadataRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = CreateMetadataRequest() # Call the method try: - method = getattr(self.media_client, "finalize_media_upload") + method = getattr(self.media_client, "create_metadata") result = method(**kwargs) # Verify the request was made mock_session.post.assert_called_once() @@ -853,7 +858,7 @@ def test_finalize_media_upload_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/media/upload/{id}/finalize" + expected_path = "/2/media/metadata" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -862,12 +867,12 @@ def test_finalize_media_upload_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for finalize_media_upload: {e}") + pytest.fail(f"Contract test failed for create_metadata: {e}") - def test_finalize_media_upload_required_parameters(self): - """Test that finalize_media_upload handles parameters correctly.""" - method = getattr(self.media_client, "finalize_media_upload") + def test_create_metadata_required_parameters(self): + """Test that create_metadata handles parameters correctly.""" + method = getattr(self.media_client, "create_metadata") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -881,8 +886,8 @@ def test_finalize_media_upload_required_parameters(self): method() - def test_finalize_media_upload_response_structure(self): - """Test finalize_media_upload response structure validation.""" + def test_create_metadata_response_structure(self): + """Test create_metadata response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -895,10 +900,13 @@ def test_finalize_media_upload_response_structure(self): mock_session.post.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["id"] = "test" # Add request body if required + # Import and create proper request model instance + from xdk.media.models import CreateMetadataRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = CreateMetadataRequest() # Call method and verify response structure - method = getattr(self.media_client, "finalize_media_upload") + method = getattr(self.media_client, "create_metadata") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -910,8 +918,8 @@ def test_finalize_media_upload_response_structure(self): ) - def test_append_media_upload_request_structure(self): - """Test append_media_upload request structure.""" + def test_get_by_keys_request_structure(self): + """Test get_by_keys request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -920,29 +928,25 @@ def test_append_media_upload_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["id"] = "test_value" + kwargs["media_keys"] = ["test_item"] # Add request body if required - # Import and create proper request model instance - from xdk.media.models import AppendMediaUploadRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = AppendMediaUploadRequest() # Call the method try: - method = getattr(self.media_client, "append_media_upload") + method = getattr(self.media_client, "get_by_keys") result = method(**kwargs) # Verify the request was made - mock_session.post.assert_called_once() + mock_session.get.assert_called_once() # Verify request structure - call_args = mock_session.post.call_args + call_args = mock_session.get.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/media/upload/{id}/append" + expected_path = "/2/media" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -951,12 +955,12 @@ def test_append_media_upload_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for append_media_upload: {e}") + pytest.fail(f"Contract test failed for get_by_keys: {e}") - def test_append_media_upload_required_parameters(self): - """Test that append_media_upload handles parameters correctly.""" - method = getattr(self.media_client, "append_media_upload") + def test_get_by_keys_required_parameters(self): + """Test that get_by_keys handles parameters correctly.""" + method = getattr(self.media_client, "get_by_keys") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -964,14 +968,14 @@ def test_append_media_upload_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_append_media_upload_response_structure(self): - """Test append_media_upload response structure validation.""" + def test_get_by_keys_response_structure(self): + """Test get_by_keys response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -981,17 +985,13 @@ def test_append_media_upload_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["id"] = "test" + kwargs["media_keys"] = ["test"] # Add request body if required - # Import and create proper request model instance - from xdk.media.models import AppendMediaUploadRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = AppendMediaUploadRequest() # Call method and verify response structure - method = getattr(self.media_client, "append_media_upload") + method = getattr(self.media_client, "get_by_keys") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed diff --git a/xdk/python/tests/media/test_generic.py b/xdk/python/tests/media/test_generic.py index 20e5e453..fb9d8d42 100644 --- a/xdk/python/tests/media/test_generic.py +++ b/xdk/python/tests/media/test_generic.py @@ -1,5 +1,5 @@ """ -Auto-generated generic tests for Media client. +Auto-generated generic tests for {"class_name": "Media", "display_name": "media", "import_name": "media", "original": ["media"], "property_name": "media"} client. This module contains general tests that validate the overall client functionality, imports, and error handling that don't need to be diff --git a/xdk/python/tests/media/test_structure.py b/xdk/python/tests/media/test_structure.py index 387cd493..12a8810f 100644 --- a/xdk/python/tests/media/test_structure.py +++ b/xdk/python/tests/media/test_structure.py @@ -1,8 +1,8 @@ """ -Auto-generated structural tests for Media client. +Auto-generated structural tests for {"class_name": "Media", "display_name": "media", "import_name": "media", "original": ["media"], "property_name": "media"} client. This module contains tests that validate the structure and API surface -of the Media client. These tests ensure that all expected methods +of the {"class_name": "Media", "display_name": "media", "import_name": "media", "original": ["media"], "property_name": "media"} client. These tests ensure that all expected methods exist and have the correct signatures. Generated automatically - do not edit manually. @@ -25,22 +25,22 @@ def setup_class(self): self.media_client = getattr(self.client, "media") - def test_create_media_metadata_exists(self): - """Test that create_media_metadata method exists with correct signature.""" + def test_initialize_upload_exists(self): + """Test that initialize_upload method exists with correct signature.""" # Check method exists - method = getattr(MediaClient, "create_media_metadata", None) + method = getattr(MediaClient, "initialize_upload", None) assert ( method is not None - ), f"Method create_media_metadata does not exist on MediaClient" + ), f"Method initialize_upload does not exist on MediaClient" # Check method is callable - assert callable(method), f"create_media_metadata is not callable" + assert callable(method), f"initialize_upload is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"create_media_metadata should have at least 'self' parameter" + ), f"initialize_upload should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -49,7 +49,7 @@ def test_create_media_metadata_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from create_media_metadata" + ), f"Required parameter '{required_param}' missing from initialize_upload" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -60,32 +60,32 @@ def test_create_media_metadata_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_create_media_metadata_return_annotation(self): - """Test that create_media_metadata has proper return type annotation.""" - method = getattr(MediaClient, "create_media_metadata") + def test_initialize_upload_return_annotation(self): + """Test that initialize_upload has proper return type annotation.""" + method = getattr(MediaClient, "initialize_upload") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method create_media_metadata should have return type annotation" + ), f"Method initialize_upload should have return type annotation" - def test_create_media_subtitles_exists(self): - """Test that create_media_subtitles method exists with correct signature.""" + def test_create_subtitles_exists(self): + """Test that create_subtitles method exists with correct signature.""" # Check method exists - method = getattr(MediaClient, "create_media_subtitles", None) + method = getattr(MediaClient, "create_subtitles", None) assert ( method is not None - ), f"Method create_media_subtitles does not exist on MediaClient" + ), f"Method create_subtitles does not exist on MediaClient" # Check method is callable - assert callable(method), f"create_media_subtitles is not callable" + assert callable(method), f"create_subtitles is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"create_media_subtitles should have at least 'self' parameter" + ), f"create_subtitles should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -94,7 +94,7 @@ def test_create_media_subtitles_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from create_media_subtitles" + ), f"Required parameter '{required_param}' missing from create_subtitles" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -105,32 +105,32 @@ def test_create_media_subtitles_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_create_media_subtitles_return_annotation(self): - """Test that create_media_subtitles has proper return type annotation.""" - method = getattr(MediaClient, "create_media_subtitles") + def test_create_subtitles_return_annotation(self): + """Test that create_subtitles has proper return type annotation.""" + method = getattr(MediaClient, "create_subtitles") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method create_media_subtitles should have return type annotation" + ), f"Method create_subtitles should have return type annotation" - def test_delete_media_subtitles_exists(self): - """Test that delete_media_subtitles method exists with correct signature.""" + def test_delete_subtitles_exists(self): + """Test that delete_subtitles method exists with correct signature.""" # Check method exists - method = getattr(MediaClient, "delete_media_subtitles", None) + method = getattr(MediaClient, "delete_subtitles", None) assert ( method is not None - ), f"Method delete_media_subtitles does not exist on MediaClient" + ), f"Method delete_subtitles does not exist on MediaClient" # Check method is callable - assert callable(method), f"delete_media_subtitles is not callable" + assert callable(method), f"delete_subtitles is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"delete_media_subtitles should have at least 'self' parameter" + ), f"delete_subtitles should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -139,7 +139,7 @@ def test_delete_media_subtitles_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from delete_media_subtitles" + ), f"Required parameter '{required_param}' missing from delete_subtitles" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -150,47 +150,41 @@ def test_delete_media_subtitles_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_delete_media_subtitles_return_annotation(self): - """Test that delete_media_subtitles has proper return type annotation.""" - method = getattr(MediaClient, "delete_media_subtitles") + def test_delete_subtitles_return_annotation(self): + """Test that delete_subtitles has proper return type annotation.""" + method = getattr(MediaClient, "delete_subtitles") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method delete_media_subtitles should have return type annotation" + ), f"Method delete_subtitles should have return type annotation" - def test_get_media_upload_status_exists(self): - """Test that get_media_upload_status method exists with correct signature.""" + def test_append_upload_exists(self): + """Test that append_upload method exists with correct signature.""" # Check method exists - method = getattr(MediaClient, "get_media_upload_status", None) - assert ( - method is not None - ), f"Method get_media_upload_status does not exist on MediaClient" + method = getattr(MediaClient, "append_upload", None) + assert method is not None, f"Method append_upload does not exist on MediaClient" # Check method is callable - assert callable(method), f"get_media_upload_status is not callable" + assert callable(method), f"append_upload is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_media_upload_status should have at least 'self' parameter" + assert len(params) >= 1, f"append_upload should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "media_id", + "id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_media_upload_status" + ), f"Required parameter '{required_param}' missing from append_upload" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "command", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -199,39 +193,47 @@ def test_get_media_upload_status_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_media_upload_status_return_annotation(self): - """Test that get_media_upload_status has proper return type annotation.""" - method = getattr(MediaClient, "get_media_upload_status") + def test_append_upload_return_annotation(self): + """Test that append_upload has proper return type annotation.""" + method = getattr(MediaClient, "append_upload") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_media_upload_status should have return type annotation" + ), f"Method append_upload should have return type annotation" - def test_media_upload_exists(self): - """Test that media_upload method exists with correct signature.""" + def test_get_upload_status_exists(self): + """Test that get_upload_status method exists with correct signature.""" # Check method exists - method = getattr(MediaClient, "media_upload", None) - assert method is not None, f"Method media_upload does not exist on MediaClient" + method = getattr(MediaClient, "get_upload_status", None) + assert ( + method is not None + ), f"Method get_upload_status does not exist on MediaClient" # Check method is callable - assert callable(method), f"media_upload is not callable" + assert callable(method), f"get_upload_status is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"media_upload should have at least 'self' parameter" + assert ( + len(params) >= 1 + ), f"get_upload_status should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [] + required_params = [ + "media_id", + ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from media_upload" + ), f"Required parameter '{required_param}' missing from get_upload_status" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "command", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -240,32 +242,28 @@ def test_media_upload_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_media_upload_return_annotation(self): - """Test that media_upload has proper return type annotation.""" - method = getattr(MediaClient, "media_upload") + def test_get_upload_status_return_annotation(self): + """Test that get_upload_status has proper return type annotation.""" + method = getattr(MediaClient, "get_upload_status") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method media_upload should have return type annotation" + ), f"Method get_upload_status should have return type annotation" - def test_initialize_media_upload_exists(self): - """Test that initialize_media_upload method exists with correct signature.""" + def test_upload_exists(self): + """Test that upload method exists with correct signature.""" # Check method exists - method = getattr(MediaClient, "initialize_media_upload", None) - assert ( - method is not None - ), f"Method initialize_media_upload does not exist on MediaClient" + method = getattr(MediaClient, "upload", None) + assert method is not None, f"Method upload does not exist on MediaClient" # Check method is callable - assert callable(method), f"initialize_media_upload is not callable" + assert callable(method), f"upload is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"initialize_media_upload should have at least 'self' parameter" + assert len(params) >= 1, f"upload should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -274,7 +272,7 @@ def test_initialize_media_upload_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from initialize_media_upload" + ), f"Required parameter '{required_param}' missing from upload" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -285,46 +283,43 @@ def test_initialize_media_upload_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_initialize_media_upload_return_annotation(self): - """Test that initialize_media_upload has proper return type annotation.""" - method = getattr(MediaClient, "initialize_media_upload") + def test_upload_return_annotation(self): + """Test that upload has proper return type annotation.""" + method = getattr(MediaClient, "upload") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method initialize_media_upload should have return type annotation" + ), f"Method upload should have return type annotation" - def test_get_media_analytics_exists(self): - """Test that get_media_analytics method exists with correct signature.""" + def test_finalize_upload_exists(self): + """Test that finalize_upload method exists with correct signature.""" # Check method exists - method = getattr(MediaClient, "get_media_analytics", None) + method = getattr(MediaClient, "finalize_upload", None) assert ( method is not None - ), f"Method get_media_analytics does not exist on MediaClient" + ), f"Method finalize_upload does not exist on MediaClient" # Check method is callable - assert callable(method), f"get_media_analytics is not callable" + assert callable(method), f"finalize_upload is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"get_media_analytics should have at least 'self' parameter" + ), f"finalize_upload should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "media_keys", - "end_time", - "start_time", - "granularity", + "id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_media_analytics" + ), f"Required parameter '{required_param}' missing from finalize_upload" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -335,43 +330,42 @@ def test_get_media_analytics_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_media_analytics_return_annotation(self): - """Test that get_media_analytics has proper return type annotation.""" - method = getattr(MediaClient, "get_media_analytics") + def test_finalize_upload_return_annotation(self): + """Test that finalize_upload has proper return type annotation.""" + method = getattr(MediaClient, "finalize_upload") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_media_analytics should have return type annotation" + ), f"Method finalize_upload should have return type annotation" - def test_get_media_by_media_keys_exists(self): - """Test that get_media_by_media_keys method exists with correct signature.""" + def test_get_analytics_exists(self): + """Test that get_analytics method exists with correct signature.""" # Check method exists - method = getattr(MediaClient, "get_media_by_media_keys", None) - assert ( - method is not None - ), f"Method get_media_by_media_keys does not exist on MediaClient" + method = getattr(MediaClient, "get_analytics", None) + assert method is not None, f"Method get_analytics does not exist on MediaClient" # Check method is callable - assert callable(method), f"get_media_by_media_keys is not callable" + assert callable(method), f"get_analytics is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_media_by_media_keys should have at least 'self' parameter" + assert len(params) >= 1, f"get_analytics should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ "media_keys", + "end_time", + "start_time", + "granularity", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_media_by_media_keys" + ), f"Required parameter '{required_param}' missing from get_analytics" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -382,32 +376,28 @@ def test_get_media_by_media_keys_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_media_by_media_keys_return_annotation(self): - """Test that get_media_by_media_keys has proper return type annotation.""" - method = getattr(MediaClient, "get_media_by_media_keys") + def test_get_analytics_return_annotation(self): + """Test that get_analytics has proper return type annotation.""" + method = getattr(MediaClient, "get_analytics") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_media_by_media_keys should have return type annotation" + ), f"Method get_analytics should have return type annotation" - def test_get_media_by_media_key_exists(self): - """Test that get_media_by_media_key method exists with correct signature.""" + def test_get_by_key_exists(self): + """Test that get_by_key method exists with correct signature.""" # Check method exists - method = getattr(MediaClient, "get_media_by_media_key", None) - assert ( - method is not None - ), f"Method get_media_by_media_key does not exist on MediaClient" + method = getattr(MediaClient, "get_by_key", None) + assert method is not None, f"Method get_by_key does not exist on MediaClient" # Check method is callable - assert callable(method), f"get_media_by_media_key is not callable" + assert callable(method), f"get_by_key is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_media_by_media_key should have at least 'self' parameter" + assert len(params) >= 1, f"get_by_key should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -418,7 +408,7 @@ def test_get_media_by_media_key_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_media_by_media_key" + ), f"Required parameter '{required_param}' missing from get_by_key" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -429,43 +419,41 @@ def test_get_media_by_media_key_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_media_by_media_key_return_annotation(self): - """Test that get_media_by_media_key has proper return type annotation.""" - method = getattr(MediaClient, "get_media_by_media_key") + def test_get_by_key_return_annotation(self): + """Test that get_by_key has proper return type annotation.""" + method = getattr(MediaClient, "get_by_key") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_media_by_media_key should have return type annotation" + ), f"Method get_by_key should have return type annotation" - def test_finalize_media_upload_exists(self): - """Test that finalize_media_upload method exists with correct signature.""" + def test_create_metadata_exists(self): + """Test that create_metadata method exists with correct signature.""" # Check method exists - method = getattr(MediaClient, "finalize_media_upload", None) + method = getattr(MediaClient, "create_metadata", None) assert ( method is not None - ), f"Method finalize_media_upload does not exist on MediaClient" + ), f"Method create_metadata does not exist on MediaClient" # Check method is callable - assert callable(method), f"finalize_media_upload is not callable" + assert callable(method), f"create_metadata is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"finalize_media_upload should have at least 'self' parameter" + ), f"create_metadata should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] + required_params = [] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from finalize_media_upload" + ), f"Required parameter '{required_param}' missing from create_metadata" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -476,43 +464,39 @@ def test_finalize_media_upload_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_finalize_media_upload_return_annotation(self): - """Test that finalize_media_upload has proper return type annotation.""" - method = getattr(MediaClient, "finalize_media_upload") + def test_create_metadata_return_annotation(self): + """Test that create_metadata has proper return type annotation.""" + method = getattr(MediaClient, "create_metadata") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method finalize_media_upload should have return type annotation" + ), f"Method create_metadata should have return type annotation" - def test_append_media_upload_exists(self): - """Test that append_media_upload method exists with correct signature.""" + def test_get_by_keys_exists(self): + """Test that get_by_keys method exists with correct signature.""" # Check method exists - method = getattr(MediaClient, "append_media_upload", None) - assert ( - method is not None - ), f"Method append_media_upload does not exist on MediaClient" + method = getattr(MediaClient, "get_by_keys", None) + assert method is not None, f"Method get_by_keys does not exist on MediaClient" # Check method is callable - assert callable(method), f"append_media_upload is not callable" + assert callable(method), f"get_by_keys is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"append_media_upload should have at least 'self' parameter" + assert len(params) >= 1, f"get_by_keys should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "id", + "media_keys", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from append_media_upload" + ), f"Required parameter '{required_param}' missing from get_by_keys" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -523,30 +507,30 @@ def test_append_media_upload_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_append_media_upload_return_annotation(self): - """Test that append_media_upload has proper return type annotation.""" - method = getattr(MediaClient, "append_media_upload") + def test_get_by_keys_return_annotation(self): + """Test that get_by_keys has proper return type annotation.""" + method = getattr(MediaClient, "get_by_keys") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method append_media_upload should have return type annotation" + ), f"Method get_by_keys should have return type annotation" def test_all_expected_methods_exist(self): """Test that all expected methods exist on the client.""" expected_methods = [ - "create_media_metadata", - "create_media_subtitles", - "delete_media_subtitles", - "get_media_upload_status", - "media_upload", - "initialize_media_upload", - "get_media_analytics", - "get_media_by_media_keys", - "get_media_by_media_key", - "finalize_media_upload", - "append_media_upload", + "initialize_upload", + "create_subtitles", + "delete_subtitles", + "append_upload", + "get_upload_status", + "upload", + "finalize_upload", + "get_analytics", + "get_by_key", + "create_metadata", + "get_by_keys", ] for expected_method in expected_methods: assert hasattr( diff --git a/xdk/python/tests/__init__.py b/xdk/python/tests/posts/__init__.py similarity index 100% rename from xdk/python/tests/__init__.py rename to xdk/python/tests/posts/__init__.py diff --git a/xdk/python/xdk/python/tests/users/test_contracts.py b/xdk/python/tests/posts/test_contracts.py similarity index 76% rename from xdk/python/xdk/python/tests/users/test_contracts.py rename to xdk/python/tests/posts/test_contracts.py index 0e4a69c8..abfef0b8 100644 --- a/xdk/python/xdk/python/tests/users/test_contracts.py +++ b/xdk/python/tests/posts/test_contracts.py @@ -1,8 +1,8 @@ """ -Auto-generated contract tests for Users client. +Auto-generated contract tests for {"class_name": "Posts", "display_name": "posts", "import_name": "posts", "original": ["posts"], "property_name": "posts"} client. This module contains tests that validate the request/response contracts -of the Users client against the OpenAPI specification. +of the {"class_name": "Posts", "display_name": "posts", "import_name": "posts", "original": ["posts"], "property_name": "posts"} client against the OpenAPI specification. Generated automatically - do not edit manually. """ @@ -10,22 +10,22 @@ import pytest import json from unittest.mock import Mock, patch -from xdk.users.client import UsersClient +from xdk.posts.client import PostsClient from xdk import Client -class TestUsersContracts: - """Test the API contracts of UsersClient.""" +class TestPostsContracts: + """Test the API contracts of PostsClient.""" def setup_class(self): """Set up test fixtures.""" self.client = Client(base_url="https://api.example.com") - self.users_client = getattr(self.client, "users") + self.posts_client = getattr(self.client, "posts") - def test_get_users_blocking_request_structure(self): - """Test get_users_blocking request structure.""" + def test_get_insights_historical_request_structure(self): + """Test get_insights_historical request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -38,11 +38,15 @@ def test_get_users_blocking_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["id"] = "test_value" + kwargs["tweet_ids"] = ["test_item"] + kwargs["end_time"] = "test_end_time" + kwargs["start_time"] = "test_start_time" + kwargs["granularity"] = "test_granularity" + kwargs["requested_metrics"] = ["test_item"] # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_users_blocking") + method = getattr(self.posts_client, "get_insights_historical") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -52,7 +56,7 @@ def test_get_users_blocking_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/blocking" + expected_path = "/2/insights/historical" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -61,12 +65,12 @@ def test_get_users_blocking_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_blocking: {e}") + pytest.fail(f"Contract test failed for get_insights_historical: {e}") - def test_get_users_blocking_required_parameters(self): - """Test that get_users_blocking handles parameters correctly.""" - method = getattr(self.users_client, "get_users_blocking") + def test_get_insights_historical_required_parameters(self): + """Test that get_insights_historical handles parameters correctly.""" + method = getattr(self.posts_client, "get_insights_historical") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -80,8 +84,8 @@ def test_get_users_blocking_required_parameters(self): method() - def test_get_users_blocking_response_structure(self): - """Test get_users_blocking response structure validation.""" + def test_get_insights_historical_response_structure(self): + """Test get_insights_historical response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -94,10 +98,14 @@ def test_get_users_blocking_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["id"] = "test" + kwargs["tweet_ids"] = ["test"] + kwargs["end_time"] = "test_value" + kwargs["start_time"] = "test_value" + kwargs["granularity"] = "test_value" + kwargs["requested_metrics"] = ["test"] # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_users_blocking") + method = getattr(self.posts_client, "get_insights_historical") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -109,8 +117,8 @@ def test_get_users_blocking_response_structure(self): ) - def test_get_lists_members_request_structure(self): - """Test get_lists_members request structure.""" + def test_get_counts_recent_request_structure(self): + """Test get_counts_recent request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -123,11 +131,11 @@ def test_get_lists_members_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["id"] = "test_value" + kwargs["query"] = "test_query" # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_lists_members") + method = getattr(self.posts_client, "get_counts_recent") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -137,7 +145,7 @@ def test_get_lists_members_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/lists/{id}/members" + expected_path = "/2/tweets/counts/recent" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -146,12 +154,12 @@ def test_get_lists_members_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_lists_members: {e}") + pytest.fail(f"Contract test failed for get_counts_recent: {e}") - def test_get_lists_members_required_parameters(self): - """Test that get_lists_members handles parameters correctly.""" - method = getattr(self.users_client, "get_lists_members") + def test_get_counts_recent_required_parameters(self): + """Test that get_counts_recent handles parameters correctly.""" + method = getattr(self.posts_client, "get_counts_recent") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -165,8 +173,8 @@ def test_get_lists_members_required_parameters(self): method() - def test_get_lists_members_response_structure(self): - """Test get_lists_members response structure validation.""" + def test_get_counts_recent_response_structure(self): + """Test get_counts_recent response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -179,10 +187,10 @@ def test_get_lists_members_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["id"] = "test" + kwargs["query"] = "test_value" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_lists_members") + method = getattr(self.posts_client, "get_counts_recent") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -194,8 +202,8 @@ def test_get_lists_members_response_structure(self): ) - def test_get_users_by_usernames_request_structure(self): - """Test get_users_by_usernames request structure.""" + def test_get_by_ids_request_structure(self): + """Test get_by_ids request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -208,11 +216,11 @@ def test_get_users_by_usernames_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["usernames"] = ["test_item"] + kwargs["ids"] = ["test_item"] # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_users_by_usernames") + method = getattr(self.posts_client, "get_by_ids") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -222,7 +230,7 @@ def test_get_users_by_usernames_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/by" + expected_path = "/2/tweets" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -231,12 +239,12 @@ def test_get_users_by_usernames_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_by_usernames: {e}") + pytest.fail(f"Contract test failed for get_by_ids: {e}") - def test_get_users_by_usernames_required_parameters(self): - """Test that get_users_by_usernames handles parameters correctly.""" - method = getattr(self.users_client, "get_users_by_usernames") + def test_get_by_ids_required_parameters(self): + """Test that get_by_ids handles parameters correctly.""" + method = getattr(self.posts_client, "get_by_ids") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -250,8 +258,8 @@ def test_get_users_by_usernames_required_parameters(self): method() - def test_get_users_by_usernames_response_structure(self): - """Test get_users_by_usernames response structure validation.""" + def test_get_by_ids_response_structure(self): + """Test get_by_ids response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -264,10 +272,10 @@ def test_get_users_by_usernames_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["usernames"] = ["test"] + kwargs["ids"] = ["test"] # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_users_by_usernames") + method = getattr(self.posts_client, "get_by_ids") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -279,34 +287,38 @@ def test_get_users_by_usernames_response_structure(self): ) - def test_get_users_reposts_of_me_request_structure(self): - """Test get_users_reposts_of_me request structure.""" + def test_create_request_structure(self): + """Test create request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() - mock_response.status_code = 200 + mock_response.status_code = 201 mock_response.json.return_value = { "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters # Add request body if required + # Import and create proper request model instance + from xdk.posts.models import CreateRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = CreateRequest() # Call the method try: - method = getattr(self.users_client, "get_users_reposts_of_me") + method = getattr(self.posts_client, "create") result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.post.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.post.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/reposts_of_me" + expected_path = "/2/tweets" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -315,42 +327,46 @@ def test_get_users_reposts_of_me_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_reposts_of_me: {e}") + pytest.fail(f"Contract test failed for create: {e}") - def test_get_users_reposts_of_me_required_parameters(self): - """Test that get_users_reposts_of_me handles parameters correctly.""" - method = getattr(self.users_client, "get_users_reposts_of_me") - # No required parameters, method should be callable without args + def test_create_required_parameters(self): + """Test that create handles parameters correctly.""" + method = getattr(self.posts_client, "create") + # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: + # Mock a 400 response (typical for missing required parameters) mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: + mock_response.status_code = 400 + mock_response.json.return_value = {"error": "Missing required parameters"} + mock_response.raise_for_status.side_effect = Exception("Bad Request") + mock_session.post.return_value = mock_response + # Call without required parameters should either raise locally or via server response + with pytest.raises((TypeError, ValueError, Exception)): method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - def test_get_users_reposts_of_me_response_structure(self): - """Test get_users_reposts_of_me response structure validation.""" + def test_create_response_structure(self): + """Test create response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { "data": None, } mock_response = Mock() - mock_response.status_code = 200 + mock_response.status_code = 201 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare minimal valid parameters kwargs = {} # Add request body if required + # Import and create proper request model instance + from xdk.posts.models import CreateRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = CreateRequest() # Call method and verify response structure - method = getattr(self.users_client, "get_users_reposts_of_me") + method = getattr(self.posts_client, "create") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -362,8 +378,8 @@ def test_get_users_reposts_of_me_response_structure(self): ) - def test_search_users_request_structure(self): - """Test search_users request structure.""" + def test_get_insights28hr_request_structure(self): + """Test get_insights28hr request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -376,11 +392,13 @@ def test_search_users_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["query"] = "test_value" + kwargs["tweet_ids"] = ["test_item"] + kwargs["granularity"] = "test_granularity" + kwargs["requested_metrics"] = ["test_item"] # Add request body if required # Call the method try: - method = getattr(self.users_client, "search_users") + method = getattr(self.posts_client, "get_insights28hr") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -390,7 +408,7 @@ def test_search_users_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/search" + expected_path = "/2/insights/28hr" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -399,12 +417,12 @@ def test_search_users_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for search_users: {e}") + pytest.fail(f"Contract test failed for get_insights28hr: {e}") - def test_search_users_required_parameters(self): - """Test that search_users handles parameters correctly.""" - method = getattr(self.users_client, "search_users") + def test_get_insights28hr_required_parameters(self): + """Test that get_insights28hr handles parameters correctly.""" + method = getattr(self.posts_client, "get_insights28hr") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -418,8 +436,8 @@ def test_search_users_required_parameters(self): method() - def test_search_users_response_structure(self): - """Test search_users response structure validation.""" + def test_get_insights28hr_response_structure(self): + """Test get_insights28hr response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -432,10 +450,12 @@ def test_search_users_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["query"] = "test" + kwargs["tweet_ids"] = ["test"] + kwargs["granularity"] = "test_value" + kwargs["requested_metrics"] = ["test"] # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "search_users") + method = getattr(self.posts_client, "get_insights28hr") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -447,8 +467,8 @@ def test_search_users_response_structure(self): ) - def test_get_users_followers_request_structure(self): - """Test get_users_followers request structure.""" + def test_search_all_request_structure(self): + """Test search_all request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -461,11 +481,11 @@ def test_get_users_followers_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["id"] = "test_value" + kwargs["query"] = "test_query" # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_users_followers") + method = getattr(self.posts_client, "search_all") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -475,7 +495,7 @@ def test_get_users_followers_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/followers" + expected_path = "/2/tweets/search/all" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -484,12 +504,12 @@ def test_get_users_followers_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_followers: {e}") + pytest.fail(f"Contract test failed for search_all: {e}") - def test_get_users_followers_required_parameters(self): - """Test that get_users_followers handles parameters correctly.""" - method = getattr(self.users_client, "get_users_followers") + def test_search_all_required_parameters(self): + """Test that search_all handles parameters correctly.""" + method = getattr(self.posts_client, "search_all") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -503,8 +523,8 @@ def test_get_users_followers_required_parameters(self): method() - def test_get_users_followers_response_structure(self): - """Test get_users_followers response structure validation.""" + def test_search_all_response_structure(self): + """Test search_all response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -517,10 +537,10 @@ def test_get_users_followers_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["id"] = "test" + kwargs["query"] = "test_value" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_users_followers") + method = getattr(self.posts_client, "search_all") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -532,8 +552,8 @@ def test_get_users_followers_response_structure(self): ) - def test_get_users_following_request_structure(self): - """Test get_users_following request structure.""" + def test_get_reposted_by_request_structure(self): + """Test get_reposted_by request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -550,7 +570,7 @@ def test_get_users_following_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_users_following") + method = getattr(self.posts_client, "get_reposted_by") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -560,7 +580,7 @@ def test_get_users_following_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/following" + expected_path = "/2/tweets/{id}/retweeted_by" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -569,12 +589,12 @@ def test_get_users_following_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_following: {e}") + pytest.fail(f"Contract test failed for get_reposted_by: {e}") - def test_get_users_following_required_parameters(self): - """Test that get_users_following handles parameters correctly.""" - method = getattr(self.users_client, "get_users_following") + def test_get_reposted_by_required_parameters(self): + """Test that get_reposted_by handles parameters correctly.""" + method = getattr(self.posts_client, "get_reposted_by") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -588,8 +608,8 @@ def test_get_users_following_required_parameters(self): method() - def test_get_users_following_response_structure(self): - """Test get_users_following response structure validation.""" + def test_get_reposted_by_response_structure(self): + """Test get_reposted_by response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -605,7 +625,7 @@ def test_get_users_following_response_structure(self): kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_users_following") + method = getattr(self.posts_client, "get_reposted_by") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -617,8 +637,8 @@ def test_get_users_following_response_structure(self): ) - def test_follow_user_request_structure(self): - """Test follow_user request structure.""" + def test_get_reposts_request_structure(self): + """Test get_reposts request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -627,29 +647,25 @@ def test_follow_user_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters kwargs["id"] = "test_value" # Add request body if required - # Import and create proper request model instance - from xdk.users.models import FollowuserRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = FollowuserRequest() # Call the method try: - method = getattr(self.users_client, "follow_user") + method = getattr(self.posts_client, "get_reposts") result = method(**kwargs) # Verify the request was made - mock_session.post.assert_called_once() + mock_session.get.assert_called_once() # Verify request structure - call_args = mock_session.post.call_args + call_args = mock_session.get.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/following" + expected_path = "/2/tweets/{id}/retweets" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -658,12 +674,12 @@ def test_follow_user_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for follow_user: {e}") + pytest.fail(f"Contract test failed for get_reposts: {e}") - def test_follow_user_required_parameters(self): - """Test that follow_user handles parameters correctly.""" - method = getattr(self.users_client, "follow_user") + def test_get_reposts_required_parameters(self): + """Test that get_reposts handles parameters correctly.""" + method = getattr(self.posts_client, "get_reposts") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -671,14 +687,14 @@ def test_follow_user_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_follow_user_response_structure(self): - """Test follow_user response structure validation.""" + def test_get_reposts_response_structure(self): + """Test get_reposts response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -688,17 +704,13 @@ def test_follow_user_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" # Add request body if required - # Import and create proper request model instance - from xdk.users.models import FollowuserRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = FollowuserRequest() # Call method and verify response structure - method = getattr(self.users_client, "follow_user") + method = getattr(self.posts_client, "get_reposts") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -710,8 +722,8 @@ def test_follow_user_response_structure(self): ) - def test_get_posts_liking_users_request_structure(self): - """Test get_posts_liking_users request structure.""" + def test_get_counts_all_request_structure(self): + """Test get_counts_all request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -724,11 +736,11 @@ def test_get_posts_liking_users_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["id"] = "test_value" + kwargs["query"] = "test_query" # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_posts_liking_users") + method = getattr(self.posts_client, "get_counts_all") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -738,7 +750,7 @@ def test_get_posts_liking_users_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/tweets/{id}/liking_users" + expected_path = "/2/tweets/counts/all" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -747,12 +759,12 @@ def test_get_posts_liking_users_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_posts_liking_users: {e}") + pytest.fail(f"Contract test failed for get_counts_all: {e}") - def test_get_posts_liking_users_required_parameters(self): - """Test that get_posts_liking_users handles parameters correctly.""" - method = getattr(self.users_client, "get_posts_liking_users") + def test_get_counts_all_required_parameters(self): + """Test that get_counts_all handles parameters correctly.""" + method = getattr(self.posts_client, "get_counts_all") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -766,8 +778,8 @@ def test_get_posts_liking_users_required_parameters(self): method() - def test_get_posts_liking_users_response_structure(self): - """Test get_posts_liking_users response structure validation.""" + def test_get_counts_all_response_structure(self): + """Test get_counts_all response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -780,10 +792,10 @@ def test_get_posts_liking_users_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["id"] = "test" + kwargs["query"] = "test_value" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_posts_liking_users") + method = getattr(self.posts_client, "get_counts_all") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -795,8 +807,8 @@ def test_get_posts_liking_users_response_structure(self): ) - def test_get_posts_reposted_by_request_structure(self): - """Test get_posts_reposted_by request structure.""" + def test_search_recent_request_structure(self): + """Test search_recent request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -809,11 +821,11 @@ def test_get_posts_reposted_by_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["id"] = "test_value" + kwargs["query"] = "test_query" # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_posts_reposted_by") + method = getattr(self.posts_client, "search_recent") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -823,7 +835,7 @@ def test_get_posts_reposted_by_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/tweets/{id}/retweeted_by" + expected_path = "/2/tweets/search/recent" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -832,12 +844,12 @@ def test_get_posts_reposted_by_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_posts_reposted_by: {e}") + pytest.fail(f"Contract test failed for search_recent: {e}") - def test_get_posts_reposted_by_required_parameters(self): - """Test that get_posts_reposted_by handles parameters correctly.""" - method = getattr(self.users_client, "get_posts_reposted_by") + def test_search_recent_required_parameters(self): + """Test that search_recent handles parameters correctly.""" + method = getattr(self.posts_client, "search_recent") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -851,8 +863,8 @@ def test_get_posts_reposted_by_required_parameters(self): method() - def test_get_posts_reposted_by_response_structure(self): - """Test get_posts_reposted_by response structure validation.""" + def test_search_recent_response_structure(self): + """Test search_recent response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -865,10 +877,10 @@ def test_get_posts_reposted_by_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["id"] = "test" + kwargs["query"] = "test_value" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_posts_reposted_by") + method = getattr(self.posts_client, "search_recent") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -880,8 +892,8 @@ def test_get_posts_reposted_by_response_structure(self): ) - def test_get_users_by_id_request_structure(self): - """Test get_users_by_id request structure.""" + def test_unrepost_post_request_structure(self): + """Test unrepost_post request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -890,25 +902,26 @@ def test_get_users_by_id_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters kwargs["id"] = "test_value" + kwargs["source_tweet_id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_users_by_id") + method = getattr(self.posts_client, "unrepost_post") result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.delete.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.delete.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}" + expected_path = "/2/users/{id}/retweets/{source_tweet_id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -917,12 +930,12 @@ def test_get_users_by_id_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_by_id: {e}") + pytest.fail(f"Contract test failed for unrepost_post: {e}") - def test_get_users_by_id_required_parameters(self): - """Test that get_users_by_id handles parameters correctly.""" - method = getattr(self.users_client, "get_users_by_id") + def test_unrepost_post_required_parameters(self): + """Test that unrepost_post handles parameters correctly.""" + method = getattr(self.posts_client, "unrepost_post") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -930,14 +943,14 @@ def test_get_users_by_id_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_get_users_by_id_response_structure(self): - """Test get_users_by_id response structure validation.""" + def test_unrepost_post_response_structure(self): + """Test unrepost_post response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -947,13 +960,14 @@ def test_get_users_by_id_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" + kwargs["source_tweet_id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_users_by_id") + method = getattr(self.posts_client, "unrepost_post") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -965,8 +979,8 @@ def test_get_users_by_id_response_structure(self): ) - def test_get_users_by_ids_request_structure(self): - """Test get_users_by_ids request structure.""" + def test_get_analytics_request_structure(self): + """Test get_analytics request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -980,10 +994,13 @@ def test_get_users_by_ids_request_structure(self): kwargs = {} # Add required parameters kwargs["ids"] = ["test_item"] + kwargs["end_time"] = "test_end_time" + kwargs["start_time"] = "test_start_time" + kwargs["granularity"] = "test_granularity" # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_users_by_ids") + method = getattr(self.posts_client, "get_analytics") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -993,7 +1010,7 @@ def test_get_users_by_ids_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users" + expected_path = "/2/tweets/analytics" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1002,12 +1019,12 @@ def test_get_users_by_ids_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_by_ids: {e}") + pytest.fail(f"Contract test failed for get_analytics: {e}") - def test_get_users_by_ids_required_parameters(self): - """Test that get_users_by_ids handles parameters correctly.""" - method = getattr(self.users_client, "get_users_by_ids") + def test_get_analytics_required_parameters(self): + """Test that get_analytics handles parameters correctly.""" + method = getattr(self.posts_client, "get_analytics") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1021,8 +1038,8 @@ def test_get_users_by_ids_required_parameters(self): method() - def test_get_users_by_ids_response_structure(self): - """Test get_users_by_ids response structure validation.""" + def test_get_analytics_response_structure(self): + """Test get_analytics response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1036,92 +1053,12 @@ def test_get_users_by_ids_response_structure(self): # Prepare minimal valid parameters kwargs = {} kwargs["ids"] = ["test"] + kwargs["end_time"] = "test_value" + kwargs["start_time"] = "test_value" + kwargs["granularity"] = "test_value" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_users_by_ids") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_my_user_request_structure(self): - """Test get_my_user request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.users_client, "get_my_user") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/me" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_my_user: {e}") - - - def test_get_my_user_required_parameters(self): - """Test that get_my_user handles parameters correctly.""" - method = getattr(self.users_client, "get_my_user") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_get_my_user_response_structure(self): - """Test get_my_user response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.users_client, "get_my_user") + method = getattr(self.posts_client, "get_analytics") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1133,8 +1070,8 @@ def test_get_my_user_response_structure(self): ) - def test_get_lists_followers_request_structure(self): - """Test get_lists_followers request structure.""" + def test_repost_post_request_structure(self): + """Test repost_post request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1143,25 +1080,29 @@ def test_get_lists_followers_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters kwargs["id"] = "test_value" # Add request body if required + # Import and create proper request model instance + from xdk.posts.models import RepostPostRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = RepostPostRequest() # Call the method try: - method = getattr(self.users_client, "get_lists_followers") + method = getattr(self.posts_client, "repost_post") result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.post.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.post.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/lists/{id}/followers" + expected_path = "/2/users/{id}/retweets" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1170,12 +1111,12 @@ def test_get_lists_followers_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_lists_followers: {e}") + pytest.fail(f"Contract test failed for repost_post: {e}") - def test_get_lists_followers_required_parameters(self): - """Test that get_lists_followers handles parameters correctly.""" - method = getattr(self.users_client, "get_lists_followers") + def test_repost_post_required_parameters(self): + """Test that repost_post handles parameters correctly.""" + method = getattr(self.posts_client, "repost_post") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1183,14 +1124,14 @@ def test_get_lists_followers_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_get_lists_followers_response_structure(self): - """Test get_lists_followers response structure validation.""" + def test_repost_post_response_structure(self): + """Test repost_post response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1200,13 +1141,17 @@ def test_get_lists_followers_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" # Add request body if required + # Import and create proper request model instance + from xdk.posts.models import RepostPostRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = RepostPostRequest() # Call method and verify response structure - method = getattr(self.users_client, "get_lists_followers") + method = getattr(self.posts_client, "repost_post") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1218,8 +1163,8 @@ def test_get_lists_followers_response_structure(self): ) - def test_block_users_dms_request_structure(self): - """Test block_users_dms request structure.""" + def test_like_post_request_structure(self): + """Test like_post request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1234,9 +1179,13 @@ def test_block_users_dms_request_structure(self): # Add required parameters kwargs["id"] = "test_value" # Add request body if required + # Import and create proper request model instance + from xdk.posts.models import LikePostRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = LikePostRequest() # Call the method try: - method = getattr(self.users_client, "block_users_dms") + method = getattr(self.posts_client, "like_post") result = method(**kwargs) # Verify the request was made mock_session.post.assert_called_once() @@ -1246,7 +1195,7 @@ def test_block_users_dms_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/dm/block" + expected_path = "/2/users/{id}/likes" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1255,12 +1204,12 @@ def test_block_users_dms_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for block_users_dms: {e}") + pytest.fail(f"Contract test failed for like_post: {e}") - def test_block_users_dms_required_parameters(self): - """Test that block_users_dms handles parameters correctly.""" - method = getattr(self.users_client, "block_users_dms") + def test_like_post_required_parameters(self): + """Test that like_post handles parameters correctly.""" + method = getattr(self.posts_client, "like_post") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1274,8 +1223,8 @@ def test_block_users_dms_required_parameters(self): method() - def test_block_users_dms_response_structure(self): - """Test block_users_dms response structure validation.""" + def test_like_post_response_structure(self): + """Test like_post response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1290,8 +1239,12 @@ def test_block_users_dms_response_structure(self): kwargs = {} kwargs["id"] = "test" # Add request body if required + # Import and create proper request model instance + from xdk.posts.models import LikePostRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = LikePostRequest() # Call method and verify response structure - method = getattr(self.users_client, "block_users_dms") + method = getattr(self.posts_client, "like_post") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1303,8 +1256,8 @@ def test_block_users_dms_response_structure(self): ) - def test_unblock_users_dms_request_structure(self): - """Test unblock_users_dms request structure.""" + def test_hide_reply_request_structure(self): + """Test hide_reply request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1313,25 +1266,29 @@ def test_unblock_users_dms_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.put.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["id"] = "test_value" + kwargs["tweet_id"] = "test_value" # Add request body if required + # Import and create proper request model instance + from xdk.posts.models import HideReplyRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = HideReplyRequest() # Call the method try: - method = getattr(self.users_client, "unblock_users_dms") + method = getattr(self.posts_client, "hide_reply") result = method(**kwargs) # Verify the request was made - mock_session.post.assert_called_once() + mock_session.put.assert_called_once() # Verify request structure - call_args = mock_session.post.call_args + call_args = mock_session.put.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/dm/unblock" + expected_path = "/2/tweets/{tweet_id}/hidden" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1340,12 +1297,12 @@ def test_unblock_users_dms_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for unblock_users_dms: {e}") + pytest.fail(f"Contract test failed for hide_reply: {e}") - def test_unblock_users_dms_required_parameters(self): - """Test that unblock_users_dms handles parameters correctly.""" - method = getattr(self.users_client, "unblock_users_dms") + def test_hide_reply_required_parameters(self): + """Test that hide_reply handles parameters correctly.""" + method = getattr(self.posts_client, "hide_reply") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1353,14 +1310,14 @@ def test_unblock_users_dms_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response + mock_session.put.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_unblock_users_dms_response_structure(self): - """Test unblock_users_dms response structure validation.""" + def test_hide_reply_response_structure(self): + """Test hide_reply response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1370,13 +1327,17 @@ def test_unblock_users_dms_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.put.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["id"] = "test" + kwargs["tweet_id"] = "test" # Add request body if required + # Import and create proper request model instance + from xdk.posts.models import HideReplyRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = HideReplyRequest() # Call method and verify response structure - method = getattr(self.users_client, "unblock_users_dms") + method = getattr(self.posts_client, "hide_reply") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1388,8 +1349,8 @@ def test_unblock_users_dms_response_structure(self): ) - def test_get_users_muting_request_structure(self): - """Test get_users_muting request structure.""" + def test_unlike_post_request_structure(self): + """Test unlike_post request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1398,25 +1359,26 @@ def test_get_users_muting_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters kwargs["id"] = "test_value" + kwargs["tweet_id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_users_muting") + method = getattr(self.posts_client, "unlike_post") result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.delete.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.delete.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/muting" + expected_path = "/2/users/{id}/likes/{tweet_id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1425,12 +1387,12 @@ def test_get_users_muting_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_muting: {e}") + pytest.fail(f"Contract test failed for unlike_post: {e}") - def test_get_users_muting_required_parameters(self): - """Test that get_users_muting handles parameters correctly.""" - method = getattr(self.users_client, "get_users_muting") + def test_unlike_post_required_parameters(self): + """Test that unlike_post handles parameters correctly.""" + method = getattr(self.posts_client, "unlike_post") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1438,14 +1400,14 @@ def test_get_users_muting_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_get_users_muting_response_structure(self): - """Test get_users_muting response structure validation.""" + def test_unlike_post_response_structure(self): + """Test unlike_post response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1455,13 +1417,14 @@ def test_get_users_muting_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" + kwargs["tweet_id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_users_muting") + method = getattr(self.posts_client, "unlike_post") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1473,8 +1436,8 @@ def test_get_users_muting_response_structure(self): ) - def test_mute_user_request_structure(self): - """Test mute_user request structure.""" + def test_get_by_id_request_structure(self): + """Test get_by_id request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1483,29 +1446,25 @@ def test_mute_user_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters kwargs["id"] = "test_value" # Add request body if required - # Import and create proper request model instance - from xdk.users.models import MuteuserRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = MuteuserRequest() # Call the method try: - method = getattr(self.users_client, "mute_user") + method = getattr(self.posts_client, "get_by_id") result = method(**kwargs) # Verify the request was made - mock_session.post.assert_called_once() + mock_session.get.assert_called_once() # Verify request structure - call_args = mock_session.post.call_args + call_args = mock_session.get.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/muting" + expected_path = "/2/tweets/{id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1514,12 +1473,12 @@ def test_mute_user_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for mute_user: {e}") + pytest.fail(f"Contract test failed for get_by_id: {e}") - def test_mute_user_required_parameters(self): - """Test that mute_user handles parameters correctly.""" - method = getattr(self.users_client, "mute_user") + def test_get_by_id_required_parameters(self): + """Test that get_by_id handles parameters correctly.""" + method = getattr(self.posts_client, "get_by_id") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1527,14 +1486,14 @@ def test_mute_user_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_mute_user_response_structure(self): - """Test mute_user response structure validation.""" + def test_get_by_id_response_structure(self): + """Test get_by_id response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1544,17 +1503,13 @@ def test_mute_user_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" # Add request body if required - # Import and create proper request model instance - from xdk.users.models import MuteuserRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = MuteuserRequest() # Call method and verify response structure - method = getattr(self.users_client, "mute_user") + method = getattr(self.posts_client, "get_by_id") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1566,8 +1521,8 @@ def test_mute_user_response_structure(self): ) - def test_unfollow_user_request_structure(self): - """Test unfollow_user request structure.""" + def test_delete_request_structure(self): + """Test delete request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1580,12 +1535,11 @@ def test_unfollow_user_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["source_user_id"] = "test_value" - kwargs["target_user_id"] = "test_value" + kwargs["id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.users_client, "unfollow_user") + method = getattr(self.posts_client, "delete") result = method(**kwargs) # Verify the request was made mock_session.delete.assert_called_once() @@ -1595,7 +1549,7 @@ def test_unfollow_user_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{source_user_id}/following/{target_user_id}" + expected_path = "/2/tweets/{id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1604,12 +1558,12 @@ def test_unfollow_user_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for unfollow_user: {e}") + pytest.fail(f"Contract test failed for delete: {e}") - def test_unfollow_user_required_parameters(self): - """Test that unfollow_user handles parameters correctly.""" - method = getattr(self.users_client, "unfollow_user") + def test_delete_required_parameters(self): + """Test that delete handles parameters correctly.""" + method = getattr(self.posts_client, "delete") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1623,8 +1577,8 @@ def test_unfollow_user_required_parameters(self): method() - def test_unfollow_user_response_structure(self): - """Test unfollow_user response structure validation.""" + def test_delete_response_structure(self): + """Test delete response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1637,11 +1591,10 @@ def test_unfollow_user_response_structure(self): mock_session.delete.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["source_user_id"] = "test" - kwargs["target_user_id"] = "test" + kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "unfollow_user") + method = getattr(self.posts_client, "delete") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1653,8 +1606,8 @@ def test_unfollow_user_response_structure(self): ) - def test_unmute_user_request_structure(self): - """Test unmute_user request structure.""" + def test_get_liking_users_request_structure(self): + """Test get_liking_users request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1663,26 +1616,25 @@ def test_unmute_user_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["source_user_id"] = "test_value" - kwargs["target_user_id"] = "test_value" + kwargs["id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.users_client, "unmute_user") + method = getattr(self.posts_client, "get_liking_users") result = method(**kwargs) # Verify the request was made - mock_session.delete.assert_called_once() + mock_session.get.assert_called_once() # Verify request structure - call_args = mock_session.delete.call_args + call_args = mock_session.get.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{source_user_id}/muting/{target_user_id}" + expected_path = "/2/tweets/{id}/liking_users" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1691,12 +1643,12 @@ def test_unmute_user_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for unmute_user: {e}") + pytest.fail(f"Contract test failed for get_liking_users: {e}") - def test_unmute_user_required_parameters(self): - """Test that unmute_user handles parameters correctly.""" - method = getattr(self.users_client, "unmute_user") + def test_get_liking_users_required_parameters(self): + """Test that get_liking_users handles parameters correctly.""" + method = getattr(self.posts_client, "get_liking_users") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1704,14 +1656,14 @@ def test_unmute_user_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response + mock_session.get.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_unmute_user_response_structure(self): - """Test unmute_user response structure validation.""" + def test_get_liking_users_response_structure(self): + """Test get_liking_users response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1721,14 +1673,13 @@ def test_unmute_user_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["source_user_id"] = "test" - kwargs["target_user_id"] = "test" + kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "unmute_user") + method = getattr(self.posts_client, "get_liking_users") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1740,8 +1691,8 @@ def test_unmute_user_response_structure(self): ) - def test_get_users_by_username_request_structure(self): - """Test get_users_by_username request structure.""" + def test_get_quoted_request_structure(self): + """Test get_quoted request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1754,11 +1705,11 @@ def test_get_users_by_username_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["username"] = "test_username" + kwargs["id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_users_by_username") + method = getattr(self.posts_client, "get_quoted") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -1768,7 +1719,7 @@ def test_get_users_by_username_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/by/username/{username}" + expected_path = "/2/tweets/{id}/quote_tweets" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1777,12 +1728,12 @@ def test_get_users_by_username_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_by_username: {e}") + pytest.fail(f"Contract test failed for get_quoted: {e}") - def test_get_users_by_username_required_parameters(self): - """Test that get_users_by_username handles parameters correctly.""" - method = getattr(self.users_client, "get_users_by_username") + def test_get_quoted_required_parameters(self): + """Test that get_quoted handles parameters correctly.""" + method = getattr(self.posts_client, "get_quoted") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1796,8 +1747,8 @@ def test_get_users_by_username_required_parameters(self): method() - def test_get_users_by_username_response_structure(self): - """Test get_users_by_username response structure validation.""" + def test_get_quoted_response_structure(self): + """Test get_quoted response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1810,10 +1761,10 @@ def test_get_users_by_username_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["username"] = "test_value" + kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_users_by_username") + method = getattr(self.posts_client, "get_quoted") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed diff --git a/xdk/python/xdk/python/tests/lists/test_generic.py b/xdk/python/tests/posts/test_generic.py similarity index 74% rename from xdk/python/xdk/python/tests/lists/test_generic.py rename to xdk/python/tests/posts/test_generic.py index a964888a..53d8ec44 100644 --- a/xdk/python/xdk/python/tests/lists/test_generic.py +++ b/xdk/python/tests/posts/test_generic.py @@ -1,5 +1,5 @@ """ -Auto-generated generic tests for Lists client. +Auto-generated generic tests for {"class_name": "Posts", "display_name": "posts", "import_name": "posts", "original": ["posts"], "property_name": "posts"} client. This module contains general tests that validate the overall client functionality, imports, and error handling that don't need to be @@ -11,31 +11,31 @@ import pytest import inspect from unittest.mock import Mock, patch -from xdk.lists.client import ListsClient +from xdk.posts.client import PostsClient from xdk import Client -class TestListsGeneric: - """Generic tests for ListsClient.""" +class TestPostsGeneric: + """Generic tests for PostsClient.""" def setup_class(self): """Set up test fixtures.""" self.client = Client(base_url="https://api.example.com") - self.lists_client = getattr(self.client, "lists") + self.posts_client = getattr(self.client, "posts") def test_client_exists(self): - """Test that ListsClient class exists and is importable.""" - assert ListsClient is not None - assert hasattr(ListsClient, "__name__") - assert ListsClient.__name__ == "ListsClient" + """Test that PostsClient class exists and is importable.""" + assert PostsClient is not None + assert hasattr(PostsClient, "__name__") + assert PostsClient.__name__ == "PostsClient" def test_client_initialization(self): - """Test that ListsClient can be initialized properly.""" - assert self.lists_client is not None - assert isinstance(self.lists_client, ListsClient) + """Test that PostsClient can be initialized properly.""" + assert self.posts_client is not None + assert isinstance(self.posts_client, PostsClient) def test_imports_work(self): @@ -62,12 +62,12 @@ def test_error_responses_handling(self): # Get first available method for testing error handling client_methods = [ name - for name in dir(ListsClient) - if not name.startswith("_") and callable(getattr(ListsClient, name)) + for name in dir(PostsClient) + if not name.startswith("_") and callable(getattr(PostsClient, name)) ] if client_methods: method_name = client_methods[0] - method = getattr(self.lists_client, method_name) + method = getattr(self.posts_client, method_name) # Try calling the method and expect an exception with pytest.raises(Exception): try: @@ -85,30 +85,30 @@ def test_error_responses_handling(self): def test_client_has_expected_base_functionality(self): """Test that the client has expected base functionality.""" # Should be able to access the client through main Client - assert hasattr(self.client, "lists") + assert hasattr(self.client, "posts") # Client should have standard Python object features - assert hasattr(self.lists_client, "__class__") - assert hasattr(self.lists_client, "__dict__") + assert hasattr(self.posts_client, "__class__") + assert hasattr(self.posts_client, "__dict__") # Should have at least one public method public_methods = [ name - for name in dir(self.lists_client) - if not name.startswith("_") and callable(getattr(self.lists_client, name)) + for name in dir(self.posts_client) + if not name.startswith("_") and callable(getattr(self.posts_client, name)) ] assert ( len(public_methods) > 0 - ), f"ListsClient should have at least one public method" + ), f"PostsClient should have at least one public method" def test_client_method_signatures_are_valid(self): """Test that all client methods have valid Python signatures.""" public_methods = [ name - for name in dir(ListsClient) - if not name.startswith("_") and callable(getattr(ListsClient, name)) + for name in dir(PostsClient) + if not name.startswith("_") and callable(getattr(PostsClient, name)) ] for method_name in public_methods: - method = getattr(ListsClient, method_name) + method = getattr(PostsClient, method_name) # Should be able to get signature without error try: sig = inspect.signature(method) diff --git a/xdk/python/tests/posts/test_pagination.py b/xdk/python/tests/posts/test_pagination.py new file mode 100644 index 00000000..b7713b7e --- /dev/null +++ b/xdk/python/tests/posts/test_pagination.py @@ -0,0 +1,920 @@ +""" +Auto-generated pagination tests for {"class_name": "Posts", "display_name": "posts", "import_name": "posts", "original": ["posts"], "property_name": "posts"} client. + +This module contains tests that validate pagination functionality +using the Cursor class for methods that support pagination. + +Generated automatically - do not edit manually. +""" + +import pytest +from unittest.mock import Mock, patch +from xdk.posts.client import PostsClient +from xdk import Client, Cursor, cursor, PaginationError + + +class TestPostsPagination: + """Test pagination functionality for PostsClient.""" + + + def setup_class(self): + """Set up test fixtures.""" + self.client = Client(base_url="https://api.example.com") + self.posts_client = getattr(self.client, "posts") + + + def test_search_all_cursor_creation(self): + """Test that search_all can be used with Cursor.""" + method = getattr(self.posts_client, "search_all") + # Should be able to create cursor without error + try: + test_cursor = cursor(method, "test_query", max_results=10) + assert test_cursor is not None + assert isinstance(test_cursor, Cursor) + except PaginationError: + pytest.fail(f"Method search_all should support pagination") + + + def test_search_all_cursor_pages(self): + """Test pagination with pages() for search_all.""" + with patch.object(self.client, "session") as mock_session: + # Mock first page response + first_page_response = Mock() + first_page_response.status_code = 200 + first_page_response.json.return_value = { + "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], + "meta": {"next_token": "next_page_token", "result_count": 2}, + } + first_page_response.raise_for_status.return_value = None + # Mock second page response (no next token = end of pagination) + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [{"id": "3", "name": "Item 3"}], + "meta": {"result_count": 1}, + } + second_page_response.raise_for_status.return_value = None + # Return different responses for consecutive calls + mock_session.get.side_effect = [first_page_response, second_page_response] + # Test pagination + method = getattr(self.posts_client, "search_all") + test_cursor = cursor(method, "test_query", max_results=2) + pages = list(test_cursor.pages(2)) # Limit to 2 pages + assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" + # Verify first page + first_page = pages[0] + assert hasattr(first_page, "data") + first_data = getattr(first_page, "data") + assert len(first_data) == 2, "First page should have 2 items" + # Verify second page + second_page = pages[1] + assert hasattr(second_page, "data") + second_data = getattr(second_page, "data") + assert len(second_data) == 1, "Second page should have 1 item" + + + def test_search_all_cursor_items(self): + """Test pagination with items() for search_all.""" + with patch.object(self.client, "session") as mock_session: + # Mock response with paginated data + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "data": [ + {"id": "1", "name": "Item 1"}, + {"id": "2", "name": "Item 2"}, + {"id": "3", "name": "Item 3"}, + ], + "meta": { + "result_count": 3 + # No next_token = single page + }, + } + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + # Test item iteration + method = getattr(self.posts_client, "search_all") + test_cursor = cursor(method, "test_query", max_results=10) + items = list(test_cursor.items(5)) # Limit to 5 items + assert len(items) == 3, f"Should get 3 items, got {len(items)}" + # Verify items have expected structure + for item in items: + assert "id" in item or hasattr( + item, "id" + ), "Items should have 'id' field" + + + def test_search_all_pagination_parameters(self): + """Test that pagination parameters are handled correctly for search_all.""" + with patch.object(self.client, "session") as mock_session: + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + method = getattr(self.posts_client, "search_all") + # Test with max_results parameter + test_cursor = cursor(method, "test_query", max_results=5) + list(test_cursor.pages(1)) # Trigger one request + # Verify max_results was passed in request + call_args = mock_session.get.call_args + if call_args and "params" in call_args[1]: + params = call_args[1]["params"] + assert ( + "max_results" in params + ), "max_results should be in request parameters" + # Test with pagination token (simulate second page request) + mock_session.reset_mock() + mock_response_with_token = Mock() + mock_response_with_token.status_code = 200 + mock_response_with_token.json.return_value = { + "data": [{"id": "1"}], + "meta": {"next_token": "next_token_value", "result_count": 1}, + } + mock_response_with_token.raise_for_status.return_value = None + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [], + "meta": {"result_count": 0}, + } + second_page_response.raise_for_status.return_value = None + mock_session.get.side_effect = [ + mock_response_with_token, + second_page_response, + ] + test_cursor = cursor(method, "test_query", max_results=1) + pages = list(test_cursor.pages(2)) + # Should have made 2 requests + assert ( + mock_session.get.call_count == 2 + ), "Should make 2 requests for 2 pages" + # Second request should include pagination token + second_call_args = mock_session.get.call_args_list[1] + if ( + second_call_args + and len(second_call_args) > 1 + and "params" in second_call_args[1] + ): + second_params = second_call_args[1]["params"] + assert ( + "pagination_token" in second_params + ), "Second request should include pagination_token" + assert ( + second_params["pagination_token"] == "next_token_value" + ), "Pagination token should be passed correctly" + + + def test_get_reposted_by_cursor_creation(self): + """Test that get_reposted_by can be used with Cursor.""" + method = getattr(self.posts_client, "get_reposted_by") + # Should be able to create cursor without error + try: + test_cursor = cursor(method, "test_id", max_results=10) + assert test_cursor is not None + assert isinstance(test_cursor, Cursor) + except PaginationError: + pytest.fail(f"Method get_reposted_by should support pagination") + + + def test_get_reposted_by_cursor_pages(self): + """Test pagination with pages() for get_reposted_by.""" + with patch.object(self.client, "session") as mock_session: + # Mock first page response + first_page_response = Mock() + first_page_response.status_code = 200 + first_page_response.json.return_value = { + "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], + "meta": {"next_token": "next_page_token", "result_count": 2}, + } + first_page_response.raise_for_status.return_value = None + # Mock second page response (no next token = end of pagination) + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [{"id": "3", "name": "Item 3"}], + "meta": {"result_count": 1}, + } + second_page_response.raise_for_status.return_value = None + # Return different responses for consecutive calls + mock_session.get.side_effect = [first_page_response, second_page_response] + # Test pagination + method = getattr(self.posts_client, "get_reposted_by") + test_cursor = cursor(method, "test_id", max_results=2) + pages = list(test_cursor.pages(2)) # Limit to 2 pages + assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" + # Verify first page + first_page = pages[0] + assert hasattr(first_page, "data") + first_data = getattr(first_page, "data") + assert len(first_data) == 2, "First page should have 2 items" + # Verify second page + second_page = pages[1] + assert hasattr(second_page, "data") + second_data = getattr(second_page, "data") + assert len(second_data) == 1, "Second page should have 1 item" + + + def test_get_reposted_by_cursor_items(self): + """Test pagination with items() for get_reposted_by.""" + with patch.object(self.client, "session") as mock_session: + # Mock response with paginated data + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "data": [ + {"id": "1", "name": "Item 1"}, + {"id": "2", "name": "Item 2"}, + {"id": "3", "name": "Item 3"}, + ], + "meta": { + "result_count": 3 + # No next_token = single page + }, + } + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + # Test item iteration + method = getattr(self.posts_client, "get_reposted_by") + test_cursor = cursor(method, "test_id", max_results=10) + items = list(test_cursor.items(5)) # Limit to 5 items + assert len(items) == 3, f"Should get 3 items, got {len(items)}" + # Verify items have expected structure + for item in items: + assert "id" in item or hasattr( + item, "id" + ), "Items should have 'id' field" + + + def test_get_reposted_by_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_reposted_by.""" + with patch.object(self.client, "session") as mock_session: + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + method = getattr(self.posts_client, "get_reposted_by") + # Test with max_results parameter + test_cursor = cursor(method, "test_id", max_results=5) + list(test_cursor.pages(1)) # Trigger one request + # Verify max_results was passed in request + call_args = mock_session.get.call_args + if call_args and "params" in call_args[1]: + params = call_args[1]["params"] + assert ( + "max_results" in params + ), "max_results should be in request parameters" + # Test with pagination token (simulate second page request) + mock_session.reset_mock() + mock_response_with_token = Mock() + mock_response_with_token.status_code = 200 + mock_response_with_token.json.return_value = { + "data": [{"id": "1"}], + "meta": {"next_token": "next_token_value", "result_count": 1}, + } + mock_response_with_token.raise_for_status.return_value = None + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [], + "meta": {"result_count": 0}, + } + second_page_response.raise_for_status.return_value = None + mock_session.get.side_effect = [ + mock_response_with_token, + second_page_response, + ] + test_cursor = cursor(method, "test_id", max_results=1) + pages = list(test_cursor.pages(2)) + # Should have made 2 requests + assert ( + mock_session.get.call_count == 2 + ), "Should make 2 requests for 2 pages" + # Second request should include pagination token + second_call_args = mock_session.get.call_args_list[1] + if ( + second_call_args + and len(second_call_args) > 1 + and "params" in second_call_args[1] + ): + second_params = second_call_args[1]["params"] + assert ( + "pagination_token" in second_params + ), "Second request should include pagination_token" + assert ( + second_params["pagination_token"] == "next_token_value" + ), "Pagination token should be passed correctly" + + + def test_get_reposts_cursor_creation(self): + """Test that get_reposts can be used with Cursor.""" + method = getattr(self.posts_client, "get_reposts") + # Should be able to create cursor without error + try: + test_cursor = cursor(method, "test_id", max_results=10) + assert test_cursor is not None + assert isinstance(test_cursor, Cursor) + except PaginationError: + pytest.fail(f"Method get_reposts should support pagination") + + + def test_get_reposts_cursor_pages(self): + """Test pagination with pages() for get_reposts.""" + with patch.object(self.client, "session") as mock_session: + # Mock first page response + first_page_response = Mock() + first_page_response.status_code = 200 + first_page_response.json.return_value = { + "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], + "meta": {"next_token": "next_page_token", "result_count": 2}, + } + first_page_response.raise_for_status.return_value = None + # Mock second page response (no next token = end of pagination) + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [{"id": "3", "name": "Item 3"}], + "meta": {"result_count": 1}, + } + second_page_response.raise_for_status.return_value = None + # Return different responses for consecutive calls + mock_session.get.side_effect = [first_page_response, second_page_response] + # Test pagination + method = getattr(self.posts_client, "get_reposts") + test_cursor = cursor(method, "test_id", max_results=2) + pages = list(test_cursor.pages(2)) # Limit to 2 pages + assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" + # Verify first page + first_page = pages[0] + assert hasattr(first_page, "data") + first_data = getattr(first_page, "data") + assert len(first_data) == 2, "First page should have 2 items" + # Verify second page + second_page = pages[1] + assert hasattr(second_page, "data") + second_data = getattr(second_page, "data") + assert len(second_data) == 1, "Second page should have 1 item" + + + def test_get_reposts_cursor_items(self): + """Test pagination with items() for get_reposts.""" + with patch.object(self.client, "session") as mock_session: + # Mock response with paginated data + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "data": [ + {"id": "1", "name": "Item 1"}, + {"id": "2", "name": "Item 2"}, + {"id": "3", "name": "Item 3"}, + ], + "meta": { + "result_count": 3 + # No next_token = single page + }, + } + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + # Test item iteration + method = getattr(self.posts_client, "get_reposts") + test_cursor = cursor(method, "test_id", max_results=10) + items = list(test_cursor.items(5)) # Limit to 5 items + assert len(items) == 3, f"Should get 3 items, got {len(items)}" + # Verify items have expected structure + for item in items: + assert "id" in item or hasattr( + item, "id" + ), "Items should have 'id' field" + + + def test_get_reposts_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_reposts.""" + with patch.object(self.client, "session") as mock_session: + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + method = getattr(self.posts_client, "get_reposts") + # Test with max_results parameter + test_cursor = cursor(method, "test_id", max_results=5) + list(test_cursor.pages(1)) # Trigger one request + # Verify max_results was passed in request + call_args = mock_session.get.call_args + if call_args and "params" in call_args[1]: + params = call_args[1]["params"] + assert ( + "max_results" in params + ), "max_results should be in request parameters" + # Test with pagination token (simulate second page request) + mock_session.reset_mock() + mock_response_with_token = Mock() + mock_response_with_token.status_code = 200 + mock_response_with_token.json.return_value = { + "data": [{"id": "1"}], + "meta": {"next_token": "next_token_value", "result_count": 1}, + } + mock_response_with_token.raise_for_status.return_value = None + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [], + "meta": {"result_count": 0}, + } + second_page_response.raise_for_status.return_value = None + mock_session.get.side_effect = [ + mock_response_with_token, + second_page_response, + ] + test_cursor = cursor(method, "test_id", max_results=1) + pages = list(test_cursor.pages(2)) + # Should have made 2 requests + assert ( + mock_session.get.call_count == 2 + ), "Should make 2 requests for 2 pages" + # Second request should include pagination token + second_call_args = mock_session.get.call_args_list[1] + if ( + second_call_args + and len(second_call_args) > 1 + and "params" in second_call_args[1] + ): + second_params = second_call_args[1]["params"] + assert ( + "pagination_token" in second_params + ), "Second request should include pagination_token" + assert ( + second_params["pagination_token"] == "next_token_value" + ), "Pagination token should be passed correctly" + + + def test_search_recent_cursor_creation(self): + """Test that search_recent can be used with Cursor.""" + method = getattr(self.posts_client, "search_recent") + # Should be able to create cursor without error + try: + test_cursor = cursor(method, "test_query", max_results=10) + assert test_cursor is not None + assert isinstance(test_cursor, Cursor) + except PaginationError: + pytest.fail(f"Method search_recent should support pagination") + + + def test_search_recent_cursor_pages(self): + """Test pagination with pages() for search_recent.""" + with patch.object(self.client, "session") as mock_session: + # Mock first page response + first_page_response = Mock() + first_page_response.status_code = 200 + first_page_response.json.return_value = { + "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], + "meta": {"next_token": "next_page_token", "result_count": 2}, + } + first_page_response.raise_for_status.return_value = None + # Mock second page response (no next token = end of pagination) + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [{"id": "3", "name": "Item 3"}], + "meta": {"result_count": 1}, + } + second_page_response.raise_for_status.return_value = None + # Return different responses for consecutive calls + mock_session.get.side_effect = [first_page_response, second_page_response] + # Test pagination + method = getattr(self.posts_client, "search_recent") + test_cursor = cursor(method, "test_query", max_results=2) + pages = list(test_cursor.pages(2)) # Limit to 2 pages + assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" + # Verify first page + first_page = pages[0] + assert hasattr(first_page, "data") + first_data = getattr(first_page, "data") + assert len(first_data) == 2, "First page should have 2 items" + # Verify second page + second_page = pages[1] + assert hasattr(second_page, "data") + second_data = getattr(second_page, "data") + assert len(second_data) == 1, "Second page should have 1 item" + + + def test_search_recent_cursor_items(self): + """Test pagination with items() for search_recent.""" + with patch.object(self.client, "session") as mock_session: + # Mock response with paginated data + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "data": [ + {"id": "1", "name": "Item 1"}, + {"id": "2", "name": "Item 2"}, + {"id": "3", "name": "Item 3"}, + ], + "meta": { + "result_count": 3 + # No next_token = single page + }, + } + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + # Test item iteration + method = getattr(self.posts_client, "search_recent") + test_cursor = cursor(method, "test_query", max_results=10) + items = list(test_cursor.items(5)) # Limit to 5 items + assert len(items) == 3, f"Should get 3 items, got {len(items)}" + # Verify items have expected structure + for item in items: + assert "id" in item or hasattr( + item, "id" + ), "Items should have 'id' field" + + + def test_search_recent_pagination_parameters(self): + """Test that pagination parameters are handled correctly for search_recent.""" + with patch.object(self.client, "session") as mock_session: + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + method = getattr(self.posts_client, "search_recent") + # Test with max_results parameter + test_cursor = cursor(method, "test_query", max_results=5) + list(test_cursor.pages(1)) # Trigger one request + # Verify max_results was passed in request + call_args = mock_session.get.call_args + if call_args and "params" in call_args[1]: + params = call_args[1]["params"] + assert ( + "max_results" in params + ), "max_results should be in request parameters" + # Test with pagination token (simulate second page request) + mock_session.reset_mock() + mock_response_with_token = Mock() + mock_response_with_token.status_code = 200 + mock_response_with_token.json.return_value = { + "data": [{"id": "1"}], + "meta": {"next_token": "next_token_value", "result_count": 1}, + } + mock_response_with_token.raise_for_status.return_value = None + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [], + "meta": {"result_count": 0}, + } + second_page_response.raise_for_status.return_value = None + mock_session.get.side_effect = [ + mock_response_with_token, + second_page_response, + ] + test_cursor = cursor(method, "test_query", max_results=1) + pages = list(test_cursor.pages(2)) + # Should have made 2 requests + assert ( + mock_session.get.call_count == 2 + ), "Should make 2 requests for 2 pages" + # Second request should include pagination token + second_call_args = mock_session.get.call_args_list[1] + if ( + second_call_args + and len(second_call_args) > 1 + and "params" in second_call_args[1] + ): + second_params = second_call_args[1]["params"] + assert ( + "pagination_token" in second_params + ), "Second request should include pagination_token" + assert ( + second_params["pagination_token"] == "next_token_value" + ), "Pagination token should be passed correctly" + + + def test_get_liking_users_cursor_creation(self): + """Test that get_liking_users can be used with Cursor.""" + method = getattr(self.posts_client, "get_liking_users") + # Should be able to create cursor without error + try: + test_cursor = cursor(method, "test_id", max_results=10) + assert test_cursor is not None + assert isinstance(test_cursor, Cursor) + except PaginationError: + pytest.fail(f"Method get_liking_users should support pagination") + + + def test_get_liking_users_cursor_pages(self): + """Test pagination with pages() for get_liking_users.""" + with patch.object(self.client, "session") as mock_session: + # Mock first page response + first_page_response = Mock() + first_page_response.status_code = 200 + first_page_response.json.return_value = { + "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], + "meta": {"next_token": "next_page_token", "result_count": 2}, + } + first_page_response.raise_for_status.return_value = None + # Mock second page response (no next token = end of pagination) + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [{"id": "3", "name": "Item 3"}], + "meta": {"result_count": 1}, + } + second_page_response.raise_for_status.return_value = None + # Return different responses for consecutive calls + mock_session.get.side_effect = [first_page_response, second_page_response] + # Test pagination + method = getattr(self.posts_client, "get_liking_users") + test_cursor = cursor(method, "test_id", max_results=2) + pages = list(test_cursor.pages(2)) # Limit to 2 pages + assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" + # Verify first page + first_page = pages[0] + assert hasattr(first_page, "data") + first_data = getattr(first_page, "data") + assert len(first_data) == 2, "First page should have 2 items" + # Verify second page + second_page = pages[1] + assert hasattr(second_page, "data") + second_data = getattr(second_page, "data") + assert len(second_data) == 1, "Second page should have 1 item" + + + def test_get_liking_users_cursor_items(self): + """Test pagination with items() for get_liking_users.""" + with patch.object(self.client, "session") as mock_session: + # Mock response with paginated data + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "data": [ + {"id": "1", "name": "Item 1"}, + {"id": "2", "name": "Item 2"}, + {"id": "3", "name": "Item 3"}, + ], + "meta": { + "result_count": 3 + # No next_token = single page + }, + } + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + # Test item iteration + method = getattr(self.posts_client, "get_liking_users") + test_cursor = cursor(method, "test_id", max_results=10) + items = list(test_cursor.items(5)) # Limit to 5 items + assert len(items) == 3, f"Should get 3 items, got {len(items)}" + # Verify items have expected structure + for item in items: + assert "id" in item or hasattr( + item, "id" + ), "Items should have 'id' field" + + + def test_get_liking_users_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_liking_users.""" + with patch.object(self.client, "session") as mock_session: + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + method = getattr(self.posts_client, "get_liking_users") + # Test with max_results parameter + test_cursor = cursor(method, "test_id", max_results=5) + list(test_cursor.pages(1)) # Trigger one request + # Verify max_results was passed in request + call_args = mock_session.get.call_args + if call_args and "params" in call_args[1]: + params = call_args[1]["params"] + assert ( + "max_results" in params + ), "max_results should be in request parameters" + # Test with pagination token (simulate second page request) + mock_session.reset_mock() + mock_response_with_token = Mock() + mock_response_with_token.status_code = 200 + mock_response_with_token.json.return_value = { + "data": [{"id": "1"}], + "meta": {"next_token": "next_token_value", "result_count": 1}, + } + mock_response_with_token.raise_for_status.return_value = None + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [], + "meta": {"result_count": 0}, + } + second_page_response.raise_for_status.return_value = None + mock_session.get.side_effect = [ + mock_response_with_token, + second_page_response, + ] + test_cursor = cursor(method, "test_id", max_results=1) + pages = list(test_cursor.pages(2)) + # Should have made 2 requests + assert ( + mock_session.get.call_count == 2 + ), "Should make 2 requests for 2 pages" + # Second request should include pagination token + second_call_args = mock_session.get.call_args_list[1] + if ( + second_call_args + and len(second_call_args) > 1 + and "params" in second_call_args[1] + ): + second_params = second_call_args[1]["params"] + assert ( + "pagination_token" in second_params + ), "Second request should include pagination_token" + assert ( + second_params["pagination_token"] == "next_token_value" + ), "Pagination token should be passed correctly" + + + def test_get_quoted_cursor_creation(self): + """Test that get_quoted can be used with Cursor.""" + method = getattr(self.posts_client, "get_quoted") + # Should be able to create cursor without error + try: + test_cursor = cursor(method, "test_id", max_results=10) + assert test_cursor is not None + assert isinstance(test_cursor, Cursor) + except PaginationError: + pytest.fail(f"Method get_quoted should support pagination") + + + def test_get_quoted_cursor_pages(self): + """Test pagination with pages() for get_quoted.""" + with patch.object(self.client, "session") as mock_session: + # Mock first page response + first_page_response = Mock() + first_page_response.status_code = 200 + first_page_response.json.return_value = { + "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], + "meta": {"next_token": "next_page_token", "result_count": 2}, + } + first_page_response.raise_for_status.return_value = None + # Mock second page response (no next token = end of pagination) + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [{"id": "3", "name": "Item 3"}], + "meta": {"result_count": 1}, + } + second_page_response.raise_for_status.return_value = None + # Return different responses for consecutive calls + mock_session.get.side_effect = [first_page_response, second_page_response] + # Test pagination + method = getattr(self.posts_client, "get_quoted") + test_cursor = cursor(method, "test_id", max_results=2) + pages = list(test_cursor.pages(2)) # Limit to 2 pages + assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" + # Verify first page + first_page = pages[0] + assert hasattr(first_page, "data") + first_data = getattr(first_page, "data") + assert len(first_data) == 2, "First page should have 2 items" + # Verify second page + second_page = pages[1] + assert hasattr(second_page, "data") + second_data = getattr(second_page, "data") + assert len(second_data) == 1, "Second page should have 1 item" + + + def test_get_quoted_cursor_items(self): + """Test pagination with items() for get_quoted.""" + with patch.object(self.client, "session") as mock_session: + # Mock response with paginated data + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "data": [ + {"id": "1", "name": "Item 1"}, + {"id": "2", "name": "Item 2"}, + {"id": "3", "name": "Item 3"}, + ], + "meta": { + "result_count": 3 + # No next_token = single page + }, + } + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + # Test item iteration + method = getattr(self.posts_client, "get_quoted") + test_cursor = cursor(method, "test_id", max_results=10) + items = list(test_cursor.items(5)) # Limit to 5 items + assert len(items) == 3, f"Should get 3 items, got {len(items)}" + # Verify items have expected structure + for item in items: + assert "id" in item or hasattr( + item, "id" + ), "Items should have 'id' field" + + + def test_get_quoted_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_quoted.""" + with patch.object(self.client, "session") as mock_session: + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + method = getattr(self.posts_client, "get_quoted") + # Test with max_results parameter + test_cursor = cursor(method, "test_id", max_results=5) + list(test_cursor.pages(1)) # Trigger one request + # Verify max_results was passed in request + call_args = mock_session.get.call_args + if call_args and "params" in call_args[1]: + params = call_args[1]["params"] + assert ( + "max_results" in params + ), "max_results should be in request parameters" + # Test with pagination token (simulate second page request) + mock_session.reset_mock() + mock_response_with_token = Mock() + mock_response_with_token.status_code = 200 + mock_response_with_token.json.return_value = { + "data": [{"id": "1"}], + "meta": {"next_token": "next_token_value", "result_count": 1}, + } + mock_response_with_token.raise_for_status.return_value = None + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [], + "meta": {"result_count": 0}, + } + second_page_response.raise_for_status.return_value = None + mock_session.get.side_effect = [ + mock_response_with_token, + second_page_response, + ] + test_cursor = cursor(method, "test_id", max_results=1) + pages = list(test_cursor.pages(2)) + # Should have made 2 requests + assert ( + mock_session.get.call_count == 2 + ), "Should make 2 requests for 2 pages" + # Second request should include pagination token + second_call_args = mock_session.get.call_args_list[1] + if ( + second_call_args + and len(second_call_args) > 1 + and "params" in second_call_args[1] + ): + second_params = second_call_args[1]["params"] + assert ( + "pagination_token" in second_params + ), "Second request should include pagination_token" + assert ( + second_params["pagination_token"] == "next_token_value" + ), "Pagination token should be passed correctly" + + + def test_pagination_edge_cases(self): + """Test pagination edge cases.""" + with patch.object(self.client, "session") as mock_session: + # Test empty response + empty_response = Mock() + empty_response.status_code = 200 + empty_response.json.return_value = {"data": [], "meta": {"result_count": 0}} + empty_response.raise_for_status.return_value = None + mock_session.get.return_value = empty_response + # Pick first paginatable method for testing + method = getattr(self.posts_client, "search_all") + test_cursor = cursor(method, "test_query", max_results=10) + # Should handle empty responses gracefully + pages = list(test_cursor.pages(1)) + assert len(pages) == 1, "Should get one page even if empty" + items = list(test_cursor.items(10)) + assert len(items) == 0, "Should get no items from empty response" + + + def test_non_paginatable_method_raises_error(self): + """Test that non-paginatable methods raise PaginationError.""" + # Create a mock method that doesn't support pagination + def non_paginatable_method(id: str) -> dict: + return {"id": id} + with pytest.raises(PaginationError): + cursor(non_paginatable_method) + + + def non_paginatable_method(id: str) -> dict: + return {"id": id} + + with pytest.raises(PaginationError): + cursor(non_paginatable_method) + + + def test_cursor_class_functionality(self): + """Test basic Cursor class functionality.""" + # Test that Cursor can be imported and instantiated + from xdk.paginator import Cursor + assert Cursor is not None + # Test cursor factory function + from xdk.paginator import cursor as cursor_factory + assert cursor_factory is not None diff --git a/xdk/python/xdk/python/tests/users/test_structure.py b/xdk/python/tests/posts/test_structure.py similarity index 57% rename from xdk/python/xdk/python/tests/users/test_structure.py rename to xdk/python/tests/posts/test_structure.py index 6f880bc9..46a73fdd 100644 --- a/xdk/python/xdk/python/tests/users/test_structure.py +++ b/xdk/python/tests/posts/test_structure.py @@ -1,8 +1,8 @@ """ -Auto-generated structural tests for Users client. +Auto-generated structural tests for {"class_name": "Posts", "display_name": "posts", "import_name": "posts", "original": ["posts"], "property_name": "posts"} client. This module contains tests that validate the structure and API surface -of the Users client. These tests ensure that all expected methods +of the {"class_name": "Posts", "display_name": "posts", "import_name": "posts", "original": ["posts"], "property_name": "posts"} client. These tests ensure that all expected methods exist and have the correct signatures. Generated automatically - do not edit manually. @@ -11,52 +11,53 @@ import pytest import inspect from typing import get_type_hints -from xdk.users.client import UsersClient +from xdk.posts.client import PostsClient from xdk import Client -class TestUsersStructure: - """Test the structure of UsersClient.""" +class TestPostsStructure: + """Test the structure of PostsClient.""" def setup_class(self): """Set up test fixtures.""" self.client = Client(base_url="https://api.example.com") - self.users_client = getattr(self.client, "users") + self.posts_client = getattr(self.client, "posts") - def test_get_users_blocking_exists(self): - """Test that get_users_blocking method exists with correct signature.""" + def test_get_insights_historical_exists(self): + """Test that get_insights_historical method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_users_blocking", None) + method = getattr(PostsClient, "get_insights_historical", None) assert ( method is not None - ), f"Method get_users_blocking does not exist on UsersClient" + ), f"Method get_insights_historical does not exist on PostsClient" # Check method is callable - assert callable(method), f"get_users_blocking is not callable" + assert callable(method), f"get_insights_historical is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"get_users_blocking should have at least 'self' parameter" + ), f"get_insights_historical should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "id", + "tweet_ids", + "end_time", + "start_time", + "granularity", + "requested_metrics", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_blocking" + ), f"Required parameter '{required_param}' missing from get_insights_historical" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -65,66 +66,52 @@ def test_get_users_blocking_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_blocking_return_annotation(self): - """Test that get_users_blocking has proper return type annotation.""" - method = getattr(UsersClient, "get_users_blocking") + def test_get_insights_historical_return_annotation(self): + """Test that get_insights_historical has proper return type annotation.""" + method = getattr(PostsClient, "get_insights_historical") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_blocking should have return type annotation" - - - def test_get_users_blocking_pagination_params(self): - """Test that get_users_blocking has pagination parameters.""" - method = getattr(UsersClient, "get_users_blocking") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_blocking should have pagination parameters" + ), f"Method get_insights_historical should have return type annotation" - def test_get_lists_members_exists(self): - """Test that get_lists_members method exists with correct signature.""" + def test_get_counts_recent_exists(self): + """Test that get_counts_recent method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_lists_members", None) + method = getattr(PostsClient, "get_counts_recent", None) assert ( method is not None - ), f"Method get_lists_members does not exist on UsersClient" + ), f"Method get_counts_recent does not exist on PostsClient" # Check method is callable - assert callable(method), f"get_lists_members is not callable" + assert callable(method), f"get_counts_recent is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"get_lists_members should have at least 'self' parameter" + ), f"get_counts_recent should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "id", + "query", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_lists_members" + ), f"Required parameter '{required_param}' missing from get_counts_recent" # Check optional parameters have defaults (excluding 'self') optional_params = [ - "max_results", + "start_time", + "end_time", + "since_id", + "until_id", + "next_token", "pagination_token", + "granularity", ] for optional_param in optional_params: if optional_param in params: @@ -134,62 +121,39 @@ def test_get_lists_members_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_lists_members_return_annotation(self): - """Test that get_lists_members has proper return type annotation.""" - method = getattr(UsersClient, "get_lists_members") + def test_get_counts_recent_return_annotation(self): + """Test that get_counts_recent has proper return type annotation.""" + method = getattr(PostsClient, "get_counts_recent") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_lists_members should have return type annotation" - - - def test_get_lists_members_pagination_params(self): - """Test that get_lists_members has pagination parameters.""" - method = getattr(UsersClient, "get_lists_members") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_lists_members should have pagination parameters" + ), f"Method get_counts_recent should have return type annotation" - def test_get_users_by_usernames_exists(self): - """Test that get_users_by_usernames method exists with correct signature.""" + def test_get_by_ids_exists(self): + """Test that get_by_ids method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_users_by_usernames", None) - assert ( - method is not None - ), f"Method get_users_by_usernames does not exist on UsersClient" + method = getattr(PostsClient, "get_by_ids", None) + assert method is not None, f"Method get_by_ids does not exist on PostsClient" # Check method is callable - assert callable(method), f"get_users_by_usernames is not callable" + assert callable(method), f"get_by_ids is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_by_usernames should have at least 'self' parameter" + assert len(params) >= 1, f"get_by_ids should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "usernames", + "ids", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_by_usernames" + ), f"Required parameter '{required_param}' missing from get_by_ids" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -200,32 +164,28 @@ def test_get_users_by_usernames_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_by_usernames_return_annotation(self): - """Test that get_users_by_usernames has proper return type annotation.""" - method = getattr(UsersClient, "get_users_by_usernames") + def test_get_by_ids_return_annotation(self): + """Test that get_by_ids has proper return type annotation.""" + method = getattr(PostsClient, "get_by_ids") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_by_usernames should have return type annotation" + ), f"Method get_by_ids should have return type annotation" - def test_get_users_reposts_of_me_exists(self): - """Test that get_users_reposts_of_me method exists with correct signature.""" + def test_create_exists(self): + """Test that create method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_users_reposts_of_me", None) - assert ( - method is not None - ), f"Method get_users_reposts_of_me does not exist on UsersClient" + method = getattr(PostsClient, "create", None) + assert method is not None, f"Method create does not exist on PostsClient" # Check method is callable - assert callable(method), f"get_users_reposts_of_me is not callable" + assert callable(method), f"create is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_reposts_of_me should have at least 'self' parameter" + assert len(params) >= 1, f"create should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -234,12 +194,9 @@ def test_get_users_reposts_of_me_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_reposts_of_me" + ), f"Required parameter '{required_param}' missing from create" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -248,63 +205,47 @@ def test_get_users_reposts_of_me_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_reposts_of_me_return_annotation(self): - """Test that get_users_reposts_of_me has proper return type annotation.""" - method = getattr(UsersClient, "get_users_reposts_of_me") + def test_create_return_annotation(self): + """Test that create has proper return type annotation.""" + method = getattr(PostsClient, "create") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_reposts_of_me should have return type annotation" + ), f"Method create should have return type annotation" - def test_get_users_reposts_of_me_pagination_params(self): - """Test that get_users_reposts_of_me has pagination parameters.""" - method = getattr(UsersClient, "get_users_reposts_of_me") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_reposts_of_me should have pagination parameters" - - - def test_search_users_exists(self): - """Test that search_users method exists with correct signature.""" + def test_get_insights28hr_exists(self): + """Test that get_insights28hr method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "search_users", None) - assert method is not None, f"Method search_users does not exist on UsersClient" + method = getattr(PostsClient, "get_insights28hr", None) + assert ( + method is not None + ), f"Method get_insights28hr does not exist on PostsClient" # Check method is callable - assert callable(method), f"search_users is not callable" + assert callable(method), f"get_insights28hr is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"search_users should have at least 'self' parameter" + assert ( + len(params) >= 1 + ), f"get_insights28hr should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "query", + "tweet_ids", + "granularity", + "requested_metrics", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from search_users" + ), f"Required parameter '{required_param}' missing from get_insights28hr" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "next_token", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -313,66 +254,49 @@ def test_search_users_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_search_users_return_annotation(self): - """Test that search_users has proper return type annotation.""" - method = getattr(UsersClient, "search_users") + def test_get_insights28hr_return_annotation(self): + """Test that get_insights28hr has proper return type annotation.""" + method = getattr(PostsClient, "get_insights28hr") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method search_users should have return type annotation" - - - def test_search_users_pagination_params(self): - """Test that search_users has pagination parameters.""" - method = getattr(UsersClient, "search_users") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method search_users should have pagination parameters" + ), f"Method get_insights28hr should have return type annotation" - def test_get_users_followers_exists(self): - """Test that get_users_followers method exists with correct signature.""" + def test_search_all_exists(self): + """Test that search_all method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_users_followers", None) - assert ( - method is not None - ), f"Method get_users_followers does not exist on UsersClient" + method = getattr(PostsClient, "search_all", None) + assert method is not None, f"Method search_all does not exist on PostsClient" # Check method is callable - assert callable(method), f"get_users_followers is not callable" + assert callable(method), f"search_all is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_followers should have at least 'self' parameter" + assert len(params) >= 1, f"search_all should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "id", + "query", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_followers" + ), f"Required parameter '{required_param}' missing from search_all" # Check optional parameters have defaults (excluding 'self') optional_params = [ + "start_time", + "end_time", + "since_id", + "until_id", "max_results", + "next_token", "pagination_token", + "sort_order", ] for optional_param in optional_params: if optional_param in params: @@ -382,19 +306,19 @@ def test_get_users_followers_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_followers_return_annotation(self): - """Test that get_users_followers has proper return type annotation.""" - method = getattr(UsersClient, "get_users_followers") + def test_search_all_return_annotation(self): + """Test that search_all has proper return type annotation.""" + method = getattr(PostsClient, "search_all") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_followers should have return type annotation" + ), f"Method search_all should have return type annotation" - def test_get_users_followers_pagination_params(self): - """Test that get_users_followers has pagination parameters.""" - method = getattr(UsersClient, "get_users_followers") + def test_search_all_pagination_params(self): + """Test that search_all has pagination parameters.""" + method = getattr(PostsClient, "search_all") sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have pagination-related parameters @@ -408,25 +332,25 @@ def test_get_users_followers_pagination_params(self): has_pagination_param = any(param in params for param in pagination_params) assert ( has_pagination_param - ), f"Paginated method get_users_followers should have pagination parameters" + ), f"Paginated method search_all should have pagination parameters" - def test_get_users_following_exists(self): - """Test that get_users_following method exists with correct signature.""" + def test_get_reposted_by_exists(self): + """Test that get_reposted_by method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_users_following", None) + method = getattr(PostsClient, "get_reposted_by", None) assert ( method is not None - ), f"Method get_users_following does not exist on UsersClient" + ), f"Method get_reposted_by does not exist on PostsClient" # Check method is callable - assert callable(method), f"get_users_following is not callable" + assert callable(method), f"get_reposted_by is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"get_users_following should have at least 'self' parameter" + ), f"get_reposted_by should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -437,7 +361,7 @@ def test_get_users_following_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_following" + ), f"Required parameter '{required_param}' missing from get_reposted_by" # Check optional parameters have defaults (excluding 'self') optional_params = [ "max_results", @@ -451,19 +375,19 @@ def test_get_users_following_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_following_return_annotation(self): - """Test that get_users_following has proper return type annotation.""" - method = getattr(UsersClient, "get_users_following") + def test_get_reposted_by_return_annotation(self): + """Test that get_reposted_by has proper return type annotation.""" + method = getattr(PostsClient, "get_reposted_by") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_following should have return type annotation" + ), f"Method get_reposted_by should have return type annotation" - def test_get_users_following_pagination_params(self): - """Test that get_users_following has pagination parameters.""" - method = getattr(UsersClient, "get_users_following") + def test_get_reposted_by_pagination_params(self): + """Test that get_reposted_by has pagination parameters.""" + method = getattr(PostsClient, "get_reposted_by") sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have pagination-related parameters @@ -477,21 +401,21 @@ def test_get_users_following_pagination_params(self): has_pagination_param = any(param in params for param in pagination_params) assert ( has_pagination_param - ), f"Paginated method get_users_following should have pagination parameters" + ), f"Paginated method get_reposted_by should have pagination parameters" - def test_follow_user_exists(self): - """Test that follow_user method exists with correct signature.""" + def test_get_reposts_exists(self): + """Test that get_reposts method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "follow_user", None) - assert method is not None, f"Method follow_user does not exist on UsersClient" + method = getattr(PostsClient, "get_reposts", None) + assert method is not None, f"Method get_reposts does not exist on PostsClient" # Check method is callable - assert callable(method), f"follow_user is not callable" + assert callable(method), f"get_reposts is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"follow_user should have at least 'self' parameter" + assert len(params) >= 1, f"get_reposts should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -502,9 +426,12 @@ def test_follow_user_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from follow_user" + ), f"Required parameter '{required_param}' missing from get_reposts" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "max_results", + "pagination_token", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -513,47 +440,69 @@ def test_follow_user_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_follow_user_return_annotation(self): - """Test that follow_user has proper return type annotation.""" - method = getattr(UsersClient, "follow_user") + def test_get_reposts_return_annotation(self): + """Test that get_reposts has proper return type annotation.""" + method = getattr(PostsClient, "get_reposts") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method follow_user should have return type annotation" + ), f"Method get_reposts should have return type annotation" + + + def test_get_reposts_pagination_params(self): + """Test that get_reposts has pagination parameters.""" + method = getattr(PostsClient, "get_reposts") + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have pagination-related parameters + pagination_params = [ + "pagination_token", + "max_results", + "next_token", + "cursor", + "limit", + ] + has_pagination_param = any(param in params for param in pagination_params) + assert ( + has_pagination_param + ), f"Paginated method get_reposts should have pagination parameters" - def test_get_posts_liking_users_exists(self): - """Test that get_posts_liking_users method exists with correct signature.""" + def test_get_counts_all_exists(self): + """Test that get_counts_all method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_posts_liking_users", None) + method = getattr(PostsClient, "get_counts_all", None) assert ( method is not None - ), f"Method get_posts_liking_users does not exist on UsersClient" + ), f"Method get_counts_all does not exist on PostsClient" # Check method is callable - assert callable(method), f"get_posts_liking_users is not callable" + assert callable(method), f"get_counts_all is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_posts_liking_users should have at least 'self' parameter" + assert len(params) >= 1, f"get_counts_all should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "id", + "query", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_posts_liking_users" + ), f"Required parameter '{required_param}' missing from get_counts_all" # Check optional parameters have defaults (excluding 'self') optional_params = [ - "max_results", + "start_time", + "end_time", + "since_id", + "until_id", + "next_token", "pagination_token", + "granularity", ] for optional_param in optional_params: if optional_param in params: @@ -563,66 +512,49 @@ def test_get_posts_liking_users_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_posts_liking_users_return_annotation(self): - """Test that get_posts_liking_users has proper return type annotation.""" - method = getattr(UsersClient, "get_posts_liking_users") + def test_get_counts_all_return_annotation(self): + """Test that get_counts_all has proper return type annotation.""" + method = getattr(PostsClient, "get_counts_all") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_posts_liking_users should have return type annotation" - - - def test_get_posts_liking_users_pagination_params(self): - """Test that get_posts_liking_users has pagination parameters.""" - method = getattr(UsersClient, "get_posts_liking_users") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_posts_liking_users should have pagination parameters" + ), f"Method get_counts_all should have return type annotation" - def test_get_posts_reposted_by_exists(self): - """Test that get_posts_reposted_by method exists with correct signature.""" + def test_search_recent_exists(self): + """Test that search_recent method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_posts_reposted_by", None) - assert ( - method is not None - ), f"Method get_posts_reposted_by does not exist on UsersClient" + method = getattr(PostsClient, "search_recent", None) + assert method is not None, f"Method search_recent does not exist on PostsClient" # Check method is callable - assert callable(method), f"get_posts_reposted_by is not callable" + assert callable(method), f"search_recent is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_posts_reposted_by should have at least 'self' parameter" + assert len(params) >= 1, f"search_recent should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "id", + "query", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_posts_reposted_by" + ), f"Required parameter '{required_param}' missing from search_recent" # Check optional parameters have defaults (excluding 'self') optional_params = [ + "start_time", + "end_time", + "since_id", + "until_id", "max_results", + "next_token", "pagination_token", + "sort_order", ] for optional_param in optional_params: if optional_param in params: @@ -632,19 +564,19 @@ def test_get_posts_reposted_by_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_posts_reposted_by_return_annotation(self): - """Test that get_posts_reposted_by has proper return type annotation.""" - method = getattr(UsersClient, "get_posts_reposted_by") + def test_search_recent_return_annotation(self): + """Test that search_recent has proper return type annotation.""" + method = getattr(PostsClient, "search_recent") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_posts_reposted_by should have return type annotation" + ), f"Method search_recent should have return type annotation" - def test_get_posts_reposted_by_pagination_params(self): - """Test that get_posts_reposted_by has pagination parameters.""" - method = getattr(UsersClient, "get_posts_reposted_by") + def test_search_recent_pagination_params(self): + """Test that search_recent has pagination parameters.""" + method = getattr(PostsClient, "search_recent") sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have pagination-related parameters @@ -658,36 +590,33 @@ def test_get_posts_reposted_by_pagination_params(self): has_pagination_param = any(param in params for param in pagination_params) assert ( has_pagination_param - ), f"Paginated method get_posts_reposted_by should have pagination parameters" + ), f"Paginated method search_recent should have pagination parameters" - def test_get_users_by_id_exists(self): - """Test that get_users_by_id method exists with correct signature.""" + def test_unrepost_post_exists(self): + """Test that unrepost_post method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_users_by_id", None) - assert ( - method is not None - ), f"Method get_users_by_id does not exist on UsersClient" + method = getattr(PostsClient, "unrepost_post", None) + assert method is not None, f"Method unrepost_post does not exist on PostsClient" # Check method is callable - assert callable(method), f"get_users_by_id is not callable" + assert callable(method), f"unrepost_post is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_by_id should have at least 'self' parameter" + assert len(params) >= 1, f"unrepost_post should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ "id", + "source_tweet_id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_by_id" + ), f"Required parameter '{required_param}' missing from unrepost_post" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -698,43 +627,42 @@ def test_get_users_by_id_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_by_id_return_annotation(self): - """Test that get_users_by_id has proper return type annotation.""" - method = getattr(UsersClient, "get_users_by_id") + def test_unrepost_post_return_annotation(self): + """Test that unrepost_post has proper return type annotation.""" + method = getattr(PostsClient, "unrepost_post") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_by_id should have return type annotation" + ), f"Method unrepost_post should have return type annotation" - def test_get_users_by_ids_exists(self): - """Test that get_users_by_ids method exists with correct signature.""" + def test_get_analytics_exists(self): + """Test that get_analytics method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_users_by_ids", None) - assert ( - method is not None - ), f"Method get_users_by_ids does not exist on UsersClient" + method = getattr(PostsClient, "get_analytics", None) + assert method is not None, f"Method get_analytics does not exist on PostsClient" # Check method is callable - assert callable(method), f"get_users_by_ids is not callable" + assert callable(method), f"get_analytics is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_by_ids should have at least 'self' parameter" + assert len(params) >= 1, f"get_analytics should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ "ids", + "end_time", + "start_time", + "granularity", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_by_ids" + ), f"Required parameter '{required_param}' missing from get_analytics" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -745,37 +673,39 @@ def test_get_users_by_ids_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_by_ids_return_annotation(self): - """Test that get_users_by_ids has proper return type annotation.""" - method = getattr(UsersClient, "get_users_by_ids") + def test_get_analytics_return_annotation(self): + """Test that get_analytics has proper return type annotation.""" + method = getattr(PostsClient, "get_analytics") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_by_ids should have return type annotation" + ), f"Method get_analytics should have return type annotation" - def test_get_my_user_exists(self): - """Test that get_my_user method exists with correct signature.""" + def test_repost_post_exists(self): + """Test that repost_post method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_my_user", None) - assert method is not None, f"Method get_my_user does not exist on UsersClient" + method = getattr(PostsClient, "repost_post", None) + assert method is not None, f"Method repost_post does not exist on PostsClient" # Check method is callable - assert callable(method), f"get_my_user is not callable" + assert callable(method), f"repost_post is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"get_my_user should have at least 'self' parameter" + assert len(params) >= 1, f"repost_post should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [] + required_params = [ + "id", + ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_my_user" + ), f"Required parameter '{required_param}' missing from repost_post" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -786,32 +716,28 @@ def test_get_my_user_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_my_user_return_annotation(self): - """Test that get_my_user has proper return type annotation.""" - method = getattr(UsersClient, "get_my_user") + def test_repost_post_return_annotation(self): + """Test that repost_post has proper return type annotation.""" + method = getattr(PostsClient, "repost_post") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_my_user should have return type annotation" + ), f"Method repost_post should have return type annotation" - def test_get_lists_followers_exists(self): - """Test that get_lists_followers method exists with correct signature.""" + def test_like_post_exists(self): + """Test that like_post method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_lists_followers", None) - assert ( - method is not None - ), f"Method get_lists_followers does not exist on UsersClient" + method = getattr(PostsClient, "like_post", None) + assert method is not None, f"Method like_post does not exist on PostsClient" # Check method is callable - assert callable(method), f"get_lists_followers is not callable" + assert callable(method), f"like_post is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_lists_followers should have at least 'self' parameter" + assert len(params) >= 1, f"like_post should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -822,12 +748,9 @@ def test_get_lists_followers_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_lists_followers" + ), f"Required parameter '{required_param}' missing from like_post" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -836,62 +759,39 @@ def test_get_lists_followers_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_lists_followers_return_annotation(self): - """Test that get_lists_followers has proper return type annotation.""" - method = getattr(UsersClient, "get_lists_followers") + def test_like_post_return_annotation(self): + """Test that like_post has proper return type annotation.""" + method = getattr(PostsClient, "like_post") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_lists_followers should have return type annotation" - - - def test_get_lists_followers_pagination_params(self): - """Test that get_lists_followers has pagination parameters.""" - method = getattr(UsersClient, "get_lists_followers") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_lists_followers should have pagination parameters" + ), f"Method like_post should have return type annotation" - def test_block_users_dms_exists(self): - """Test that block_users_dms method exists with correct signature.""" + def test_hide_reply_exists(self): + """Test that hide_reply method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "block_users_dms", None) - assert ( - method is not None - ), f"Method block_users_dms does not exist on UsersClient" + method = getattr(PostsClient, "hide_reply", None) + assert method is not None, f"Method hide_reply does not exist on PostsClient" # Check method is callable - assert callable(method), f"block_users_dms is not callable" + assert callable(method), f"hide_reply is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"block_users_dms should have at least 'self' parameter" + assert len(params) >= 1, f"hide_reply should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "id", + "tweet_id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from block_users_dms" + ), f"Required parameter '{required_param}' missing from hide_reply" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -902,43 +802,40 @@ def test_block_users_dms_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_block_users_dms_return_annotation(self): - """Test that block_users_dms has proper return type annotation.""" - method = getattr(UsersClient, "block_users_dms") + def test_hide_reply_return_annotation(self): + """Test that hide_reply has proper return type annotation.""" + method = getattr(PostsClient, "hide_reply") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method block_users_dms should have return type annotation" + ), f"Method hide_reply should have return type annotation" - def test_unblock_users_dms_exists(self): - """Test that unblock_users_dms method exists with correct signature.""" + def test_unlike_post_exists(self): + """Test that unlike_post method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "unblock_users_dms", None) - assert ( - method is not None - ), f"Method unblock_users_dms does not exist on UsersClient" + method = getattr(PostsClient, "unlike_post", None) + assert method is not None, f"Method unlike_post does not exist on PostsClient" # Check method is callable - assert callable(method), f"unblock_users_dms is not callable" + assert callable(method), f"unlike_post is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"unblock_users_dms should have at least 'self' parameter" + assert len(params) >= 1, f"unlike_post should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ "id", + "tweet_id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from unblock_users_dms" + ), f"Required parameter '{required_param}' missing from unlike_post" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -949,32 +846,28 @@ def test_unblock_users_dms_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_unblock_users_dms_return_annotation(self): - """Test that unblock_users_dms has proper return type annotation.""" - method = getattr(UsersClient, "unblock_users_dms") + def test_unlike_post_return_annotation(self): + """Test that unlike_post has proper return type annotation.""" + method = getattr(PostsClient, "unlike_post") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method unblock_users_dms should have return type annotation" + ), f"Method unlike_post should have return type annotation" - def test_get_users_muting_exists(self): - """Test that get_users_muting method exists with correct signature.""" + def test_get_by_id_exists(self): + """Test that get_by_id method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_users_muting", None) - assert ( - method is not None - ), f"Method get_users_muting does not exist on UsersClient" + method = getattr(PostsClient, "get_by_id", None) + assert method is not None, f"Method get_by_id does not exist on PostsClient" # Check method is callable - assert callable(method), f"get_users_muting is not callable" + assert callable(method), f"get_by_id is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_muting should have at least 'self' parameter" + assert len(params) >= 1, f"get_by_id should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -985,12 +878,9 @@ def test_get_users_muting_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_muting" + ), f"Required parameter '{required_param}' missing from get_by_id" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -999,47 +889,28 @@ def test_get_users_muting_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_muting_return_annotation(self): - """Test that get_users_muting has proper return type annotation.""" - method = getattr(UsersClient, "get_users_muting") + def test_get_by_id_return_annotation(self): + """Test that get_by_id has proper return type annotation.""" + method = getattr(PostsClient, "get_by_id") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_muting should have return type annotation" + ), f"Method get_by_id should have return type annotation" - def test_get_users_muting_pagination_params(self): - """Test that get_users_muting has pagination parameters.""" - method = getattr(UsersClient, "get_users_muting") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_muting should have pagination parameters" - - - def test_mute_user_exists(self): - """Test that mute_user method exists with correct signature.""" + def test_delete_exists(self): + """Test that delete method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "mute_user", None) - assert method is not None, f"Method mute_user does not exist on UsersClient" + method = getattr(PostsClient, "delete", None) + assert method is not None, f"Method delete does not exist on PostsClient" # Check method is callable - assert callable(method), f"mute_user is not callable" + assert callable(method), f"delete is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"mute_user should have at least 'self' parameter" + assert len(params) >= 1, f"delete should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -1050,7 +921,7 @@ def test_mute_user_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from mute_user" + ), f"Required parameter '{required_param}' missing from delete" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -1061,42 +932,48 @@ def test_mute_user_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_mute_user_return_annotation(self): - """Test that mute_user has proper return type annotation.""" - method = getattr(UsersClient, "mute_user") + def test_delete_return_annotation(self): + """Test that delete has proper return type annotation.""" + method = getattr(PostsClient, "delete") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method mute_user should have return type annotation" + ), f"Method delete should have return type annotation" - def test_unfollow_user_exists(self): - """Test that unfollow_user method exists with correct signature.""" + def test_get_liking_users_exists(self): + """Test that get_liking_users method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "unfollow_user", None) - assert method is not None, f"Method unfollow_user does not exist on UsersClient" + method = getattr(PostsClient, "get_liking_users", None) + assert ( + method is not None + ), f"Method get_liking_users does not exist on PostsClient" # Check method is callable - assert callable(method), f"unfollow_user is not callable" + assert callable(method), f"get_liking_users is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"unfollow_user should have at least 'self' parameter" + assert ( + len(params) >= 1 + ), f"get_liking_users should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "source_user_id", - "target_user_id", + "id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from unfollow_user" + ), f"Required parameter '{required_param}' missing from get_liking_users" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "max_results", + "pagination_token", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -1105,89 +982,64 @@ def test_unfollow_user_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_unfollow_user_return_annotation(self): - """Test that unfollow_user has proper return type annotation.""" - method = getattr(UsersClient, "unfollow_user") + def test_get_liking_users_return_annotation(self): + """Test that get_liking_users has proper return type annotation.""" + method = getattr(PostsClient, "get_liking_users") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method unfollow_user should have return type annotation" + ), f"Method get_liking_users should have return type annotation" - def test_unmute_user_exists(self): - """Test that unmute_user method exists with correct signature.""" - # Check method exists - method = getattr(UsersClient, "unmute_user", None) - assert method is not None, f"Method unmute_user does not exist on UsersClient" - # Check method is callable - assert callable(method), f"unmute_user is not callable" - # Check method signature + def test_get_liking_users_pagination_params(self): + """Test that get_liking_users has pagination parameters.""" + method = getattr(PostsClient, "get_liking_users") sig = inspect.signature(method) params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"unmute_user should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "source_user_id", - "target_user_id", + # Should have pagination-related parameters + pagination_params = [ + "pagination_token", + "max_results", + "next_token", + "cursor", + "limit", ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from unmute_user" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_unmute_user_return_annotation(self): - """Test that unmute_user has proper return type annotation.""" - method = getattr(UsersClient, "unmute_user") - sig = inspect.signature(method) - # Check return annotation exists + has_pagination_param = any(param in params for param in pagination_params) assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method unmute_user should have return type annotation" + has_pagination_param + ), f"Paginated method get_liking_users should have pagination parameters" - def test_get_users_by_username_exists(self): - """Test that get_users_by_username method exists with correct signature.""" + def test_get_quoted_exists(self): + """Test that get_quoted method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_users_by_username", None) - assert ( - method is not None - ), f"Method get_users_by_username does not exist on UsersClient" + method = getattr(PostsClient, "get_quoted", None) + assert method is not None, f"Method get_quoted does not exist on PostsClient" # Check method is callable - assert callable(method), f"get_users_by_username is not callable" + assert callable(method), f"get_quoted is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_by_username should have at least 'self' parameter" + assert len(params) >= 1, f"get_quoted should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "username", + "id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_by_username" + ), f"Required parameter '{required_param}' missing from get_quoted" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "max_results", + "pagination_token", + "exclude", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -1196,45 +1048,63 @@ def test_get_users_by_username_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_by_username_return_annotation(self): - """Test that get_users_by_username has proper return type annotation.""" - method = getattr(UsersClient, "get_users_by_username") + def test_get_quoted_return_annotation(self): + """Test that get_quoted has proper return type annotation.""" + method = getattr(PostsClient, "get_quoted") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_by_username should have return type annotation" + ), f"Method get_quoted should have return type annotation" + + + def test_get_quoted_pagination_params(self): + """Test that get_quoted has pagination parameters.""" + method = getattr(PostsClient, "get_quoted") + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have pagination-related parameters + pagination_params = [ + "pagination_token", + "max_results", + "next_token", + "cursor", + "limit", + ] + has_pagination_param = any(param in params for param in pagination_params) + assert ( + has_pagination_param + ), f"Paginated method get_quoted should have pagination parameters" def test_all_expected_methods_exist(self): """Test that all expected methods exist on the client.""" expected_methods = [ - "get_users_blocking", - "get_lists_members", - "get_users_by_usernames", - "get_users_reposts_of_me", - "search_users", - "get_users_followers", - "get_users_following", - "follow_user", - "get_posts_liking_users", - "get_posts_reposted_by", - "get_users_by_id", - "get_users_by_ids", - "get_my_user", - "get_lists_followers", - "block_users_dms", - "unblock_users_dms", - "get_users_muting", - "mute_user", - "unfollow_user", - "unmute_user", - "get_users_by_username", + "get_insights_historical", + "get_counts_recent", + "get_by_ids", + "create", + "get_insights28hr", + "search_all", + "get_reposted_by", + "get_reposts", + "get_counts_all", + "search_recent", + "unrepost_post", + "get_analytics", + "repost_post", + "like_post", + "hide_reply", + "unlike_post", + "get_by_id", + "delete", + "get_liking_users", + "get_quoted", ] for expected_method in expected_methods: assert hasattr( - UsersClient, expected_method - ), f"Expected method '{expected_method}' not found on UsersClient" + PostsClient, expected_method + ), f"Expected method '{expected_method}' not found on PostsClient" assert callable( - getattr(UsersClient, expected_method) + getattr(PostsClient, expected_method) ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/tests/spaces/test_contracts.py b/xdk/python/tests/spaces/test_contracts.py index 076777a5..0c4254a3 100644 --- a/xdk/python/tests/spaces/test_contracts.py +++ b/xdk/python/tests/spaces/test_contracts.py @@ -1,8 +1,8 @@ """ -Auto-generated contract tests for Spaces client. +Auto-generated contract tests for {"class_name": "Spaces", "display_name": "spaces", "import_name": "spaces", "original": ["spaces"], "property_name": "spaces"} client. This module contains tests that validate the request/response contracts -of the Spaces client against the OpenAPI specification. +of the {"class_name": "Spaces", "display_name": "spaces", "import_name": "spaces", "original": ["spaces"], "property_name": "spaces"} client against the OpenAPI specification. Generated automatically - do not edit manually. """ @@ -24,8 +24,8 @@ def setup_class(self): self.spaces_client = getattr(self.client, "spaces") - def test_get_spaces_by_id_request_structure(self): - """Test get_spaces_by_id request structure.""" + def test_get_buyers_request_structure(self): + """Test get_buyers request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -42,7 +42,7 @@ def test_get_spaces_by_id_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.spaces_client, "get_spaces_by_id") + method = getattr(self.spaces_client, "get_buyers") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -52,7 +52,7 @@ def test_get_spaces_by_id_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/spaces/{id}" + expected_path = "/2/spaces/{id}/buyers" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -61,12 +61,12 @@ def test_get_spaces_by_id_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_spaces_by_id: {e}") + pytest.fail(f"Contract test failed for get_buyers: {e}") - def test_get_spaces_by_id_required_parameters(self): - """Test that get_spaces_by_id handles parameters correctly.""" - method = getattr(self.spaces_client, "get_spaces_by_id") + def test_get_buyers_required_parameters(self): + """Test that get_buyers handles parameters correctly.""" + method = getattr(self.spaces_client, "get_buyers") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -80,8 +80,8 @@ def test_get_spaces_by_id_required_parameters(self): method() - def test_get_spaces_by_id_response_structure(self): - """Test get_spaces_by_id response structure validation.""" + def test_get_buyers_response_structure(self): + """Test get_buyers response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -97,7 +97,7 @@ def test_get_spaces_by_id_response_structure(self): kwargs["id"] = "test_value" # Add request body if required # Call method and verify response structure - method = getattr(self.spaces_client, "get_spaces_by_id") + method = getattr(self.spaces_client, "get_buyers") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -109,8 +109,8 @@ def test_get_spaces_by_id_response_structure(self): ) - def test_get_spaces_posts_request_structure(self): - """Test get_spaces_posts request structure.""" + def test_get_by_id_request_structure(self): + """Test get_by_id request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -127,7 +127,7 @@ def test_get_spaces_posts_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.spaces_client, "get_spaces_posts") + method = getattr(self.spaces_client, "get_by_id") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -137,7 +137,7 @@ def test_get_spaces_posts_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/spaces/{id}/tweets" + expected_path = "/2/spaces/{id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -146,12 +146,12 @@ def test_get_spaces_posts_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_spaces_posts: {e}") + pytest.fail(f"Contract test failed for get_by_id: {e}") - def test_get_spaces_posts_required_parameters(self): - """Test that get_spaces_posts handles parameters correctly.""" - method = getattr(self.spaces_client, "get_spaces_posts") + def test_get_by_id_required_parameters(self): + """Test that get_by_id handles parameters correctly.""" + method = getattr(self.spaces_client, "get_by_id") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -165,8 +165,8 @@ def test_get_spaces_posts_required_parameters(self): method() - def test_get_spaces_posts_response_structure(self): - """Test get_spaces_posts response structure validation.""" + def test_get_by_id_response_structure(self): + """Test get_by_id response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -182,7 +182,7 @@ def test_get_spaces_posts_response_structure(self): kwargs["id"] = "test_value" # Add request body if required # Call method and verify response structure - method = getattr(self.spaces_client, "get_spaces_posts") + method = getattr(self.spaces_client, "get_by_id") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -194,8 +194,8 @@ def test_get_spaces_posts_response_structure(self): ) - def test_get_spaces_by_creator_ids_request_structure(self): - """Test get_spaces_by_creator_ids request structure.""" + def test_get_posts_request_structure(self): + """Test get_posts request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -208,11 +208,11 @@ def test_get_spaces_by_creator_ids_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["user_ids"] = ["test_item"] + kwargs["id"] = "test_id" # Add request body if required # Call the method try: - method = getattr(self.spaces_client, "get_spaces_by_creator_ids") + method = getattr(self.spaces_client, "get_posts") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -222,7 +222,7 @@ def test_get_spaces_by_creator_ids_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/spaces/by/creator_ids" + expected_path = "/2/spaces/{id}/tweets" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -231,12 +231,12 @@ def test_get_spaces_by_creator_ids_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_spaces_by_creator_ids: {e}") + pytest.fail(f"Contract test failed for get_posts: {e}") - def test_get_spaces_by_creator_ids_required_parameters(self): - """Test that get_spaces_by_creator_ids handles parameters correctly.""" - method = getattr(self.spaces_client, "get_spaces_by_creator_ids") + def test_get_posts_required_parameters(self): + """Test that get_posts handles parameters correctly.""" + method = getattr(self.spaces_client, "get_posts") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -250,8 +250,8 @@ def test_get_spaces_by_creator_ids_required_parameters(self): method() - def test_get_spaces_by_creator_ids_response_structure(self): - """Test get_spaces_by_creator_ids response structure validation.""" + def test_get_posts_response_structure(self): + """Test get_posts response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -264,10 +264,10 @@ def test_get_spaces_by_creator_ids_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["user_ids"] = ["test"] + kwargs["id"] = "test_value" # Add request body if required # Call method and verify response structure - method = getattr(self.spaces_client, "get_spaces_by_creator_ids") + method = getattr(self.spaces_client, "get_posts") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -279,8 +279,8 @@ def test_get_spaces_by_creator_ids_response_structure(self): ) - def test_get_spaces_buyers_request_structure(self): - """Test get_spaces_buyers request structure.""" + def test_get_by_ids_request_structure(self): + """Test get_by_ids request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -293,11 +293,11 @@ def test_get_spaces_buyers_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["id"] = "test_id" + kwargs["ids"] = ["test_item"] # Add request body if required # Call the method try: - method = getattr(self.spaces_client, "get_spaces_buyers") + method = getattr(self.spaces_client, "get_by_ids") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -307,7 +307,7 @@ def test_get_spaces_buyers_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/spaces/{id}/buyers" + expected_path = "/2/spaces" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -316,12 +316,12 @@ def test_get_spaces_buyers_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_spaces_buyers: {e}") + pytest.fail(f"Contract test failed for get_by_ids: {e}") - def test_get_spaces_buyers_required_parameters(self): - """Test that get_spaces_buyers handles parameters correctly.""" - method = getattr(self.spaces_client, "get_spaces_buyers") + def test_get_by_ids_required_parameters(self): + """Test that get_by_ids handles parameters correctly.""" + method = getattr(self.spaces_client, "get_by_ids") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -335,8 +335,8 @@ def test_get_spaces_buyers_required_parameters(self): method() - def test_get_spaces_buyers_response_structure(self): - """Test get_spaces_buyers response structure validation.""" + def test_get_by_ids_response_structure(self): + """Test get_by_ids response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -349,10 +349,10 @@ def test_get_spaces_buyers_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["id"] = "test_value" + kwargs["ids"] = ["test"] # Add request body if required # Call method and verify response structure - method = getattr(self.spaces_client, "get_spaces_buyers") + method = getattr(self.spaces_client, "get_by_ids") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -364,8 +364,8 @@ def test_get_spaces_buyers_response_structure(self): ) - def test_get_spaces_by_ids_request_structure(self): - """Test get_spaces_by_ids request structure.""" + def test_search_request_structure(self): + """Test search request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -378,11 +378,11 @@ def test_get_spaces_by_ids_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["ids"] = ["test_item"] + kwargs["query"] = "test_query" # Add request body if required # Call the method try: - method = getattr(self.spaces_client, "get_spaces_by_ids") + method = getattr(self.spaces_client, "search") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -392,7 +392,7 @@ def test_get_spaces_by_ids_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/spaces" + expected_path = "/2/spaces/search" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -401,12 +401,12 @@ def test_get_spaces_by_ids_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_spaces_by_ids: {e}") + pytest.fail(f"Contract test failed for search: {e}") - def test_get_spaces_by_ids_required_parameters(self): - """Test that get_spaces_by_ids handles parameters correctly.""" - method = getattr(self.spaces_client, "get_spaces_by_ids") + def test_search_required_parameters(self): + """Test that search handles parameters correctly.""" + method = getattr(self.spaces_client, "search") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -420,8 +420,8 @@ def test_get_spaces_by_ids_required_parameters(self): method() - def test_get_spaces_by_ids_response_structure(self): - """Test get_spaces_by_ids response structure validation.""" + def test_search_response_structure(self): + """Test search response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -434,10 +434,10 @@ def test_get_spaces_by_ids_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["ids"] = ["test"] + kwargs["query"] = "test_value" # Add request body if required # Call method and verify response structure - method = getattr(self.spaces_client, "get_spaces_by_ids") + method = getattr(self.spaces_client, "search") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -449,8 +449,8 @@ def test_get_spaces_by_ids_response_structure(self): ) - def test_search_spaces_request_structure(self): - """Test search_spaces request structure.""" + def test_get_by_creator_ids_request_structure(self): + """Test get_by_creator_ids request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -463,11 +463,11 @@ def test_search_spaces_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["query"] = "test_query" + kwargs["user_ids"] = ["test_item"] # Add request body if required # Call the method try: - method = getattr(self.spaces_client, "search_spaces") + method = getattr(self.spaces_client, "get_by_creator_ids") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -477,7 +477,7 @@ def test_search_spaces_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/spaces/search" + expected_path = "/2/spaces/by/creator_ids" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -486,12 +486,12 @@ def test_search_spaces_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for search_spaces: {e}") + pytest.fail(f"Contract test failed for get_by_creator_ids: {e}") - def test_search_spaces_required_parameters(self): - """Test that search_spaces handles parameters correctly.""" - method = getattr(self.spaces_client, "search_spaces") + def test_get_by_creator_ids_required_parameters(self): + """Test that get_by_creator_ids handles parameters correctly.""" + method = getattr(self.spaces_client, "get_by_creator_ids") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -505,8 +505,8 @@ def test_search_spaces_required_parameters(self): method() - def test_search_spaces_response_structure(self): - """Test search_spaces response structure validation.""" + def test_get_by_creator_ids_response_structure(self): + """Test get_by_creator_ids response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -519,10 +519,10 @@ def test_search_spaces_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["query"] = "test_value" + kwargs["user_ids"] = ["test"] # Add request body if required # Call method and verify response structure - method = getattr(self.spaces_client, "search_spaces") + method = getattr(self.spaces_client, "get_by_creator_ids") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed diff --git a/xdk/python/tests/spaces/test_generic.py b/xdk/python/tests/spaces/test_generic.py index 8e798843..c4d9eabc 100644 --- a/xdk/python/tests/spaces/test_generic.py +++ b/xdk/python/tests/spaces/test_generic.py @@ -1,5 +1,5 @@ """ -Auto-generated generic tests for Spaces client. +Auto-generated generic tests for {"class_name": "Spaces", "display_name": "spaces", "import_name": "spaces", "original": ["spaces"], "property_name": "spaces"} client. This module contains general tests that validate the overall client functionality, imports, and error handling that don't need to be diff --git a/xdk/python/tests/spaces/test_pagination.py b/xdk/python/tests/spaces/test_pagination.py index cf6a9f4e..46615ad3 100644 --- a/xdk/python/tests/spaces/test_pagination.py +++ b/xdk/python/tests/spaces/test_pagination.py @@ -1,5 +1,5 @@ """ -Auto-generated pagination tests for Spaces client. +Auto-generated pagination tests for {"class_name": "Spaces", "display_name": "spaces", "import_name": "spaces", "original": ["spaces"], "property_name": "spaces"} client. This module contains tests that validate pagination functionality using the Cursor class for methods that support pagination. @@ -23,20 +23,20 @@ def setup_class(self): self.spaces_client = getattr(self.client, "spaces") - def test_get_spaces_buyers_cursor_creation(self): - """Test that get_spaces_buyers can be used with Cursor.""" - method = getattr(self.spaces_client, "get_spaces_buyers") + def test_get_buyers_cursor_creation(self): + """Test that get_buyers can be used with Cursor.""" + method = getattr(self.spaces_client, "get_buyers") # Should be able to create cursor without error try: test_cursor = cursor(method, "test_id", max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method getSpacesBuyers should support pagination") + pytest.fail(f"Method get_buyers should support pagination") - def test_get_spaces_buyers_cursor_pages(self): - """Test pagination with pages() for get_spaces_buyers.""" + def test_get_buyers_cursor_pages(self): + """Test pagination with pages() for get_buyers.""" with patch.object(self.client, "session") as mock_session: # Mock first page response first_page_response = Mock() @@ -57,7 +57,7 @@ def test_get_spaces_buyers_cursor_pages(self): # Return different responses for consecutive calls mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.spaces_client, "get_spaces_buyers") + method = getattr(self.spaces_client, "get_buyers") test_cursor = cursor(method, "test_id", max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" @@ -73,8 +73,8 @@ def test_get_spaces_buyers_cursor_pages(self): assert len(second_data) == 1, "Second page should have 1 item" - def test_get_spaces_buyers_cursor_items(self): - """Test pagination with items() for get_spaces_buyers.""" + def test_get_buyers_cursor_items(self): + """Test pagination with items() for get_buyers.""" with patch.object(self.client, "session") as mock_session: # Mock response with paginated data mock_response = Mock() @@ -93,7 +93,7 @@ def test_get_spaces_buyers_cursor_items(self): mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.spaces_client, "get_spaces_buyers") + method = getattr(self.spaces_client, "get_buyers") test_cursor = cursor(method, "test_id", max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items assert len(items) == 3, f"Should get 3 items, got {len(items)}" @@ -104,15 +104,15 @@ def test_get_spaces_buyers_cursor_items(self): ), "Items should have 'id' field" - def test_get_spaces_buyers_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_spaces_buyers.""" + def test_get_buyers_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_buyers.""" with patch.object(self.client, "session") as mock_session: mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.spaces_client, "get_spaces_buyers") + method = getattr(self.spaces_client, "get_buyers") # Test with max_results parameter test_cursor = cursor(method, "test_id", max_results=5) list(test_cursor.pages(1)) # Trigger one request @@ -175,7 +175,7 @@ def test_pagination_edge_cases(self): empty_response.raise_for_status.return_value = None mock_session.get.return_value = empty_response # Pick first paginatable method for testing - method = getattr(self.spaces_client, "get_spaces_buyers") + method = getattr(self.spaces_client, "get_buyers") test_cursor = cursor(method, "test_id", max_results=10) # Should handle empty responses gracefully pages = list(test_cursor.pages(1)) diff --git a/xdk/python/tests/spaces/test_structure.py b/xdk/python/tests/spaces/test_structure.py index 3b989896..63d0577d 100644 --- a/xdk/python/tests/spaces/test_structure.py +++ b/xdk/python/tests/spaces/test_structure.py @@ -1,8 +1,8 @@ """ -Auto-generated structural tests for Spaces client. +Auto-generated structural tests for {"class_name": "Spaces", "display_name": "spaces", "import_name": "spaces", "original": ["spaces"], "property_name": "spaces"} client. This module contains tests that validate the structure and API surface -of the Spaces client. These tests ensure that all expected methods +of the {"class_name": "Spaces", "display_name": "spaces", "import_name": "spaces", "original": ["spaces"], "property_name": "spaces"} client. These tests ensure that all expected methods exist and have the correct signatures. Generated automatically - do not edit manually. @@ -25,22 +25,18 @@ def setup_class(self): self.spaces_client = getattr(self.client, "spaces") - def test_get_spaces_by_id_exists(self): - """Test that get_spaces_by_id method exists with correct signature.""" + def test_get_buyers_exists(self): + """Test that get_buyers method exists with correct signature.""" # Check method exists - method = getattr(SpacesClient, "get_spaces_by_id", None) - assert ( - method is not None - ), f"Method get_spaces_by_id does not exist on SpacesClient" + method = getattr(SpacesClient, "get_buyers", None) + assert method is not None, f"Method get_buyers does not exist on SpacesClient" # Check method is callable - assert callable(method), f"get_spaces_by_id is not callable" + assert callable(method), f"get_buyers is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_spaces_by_id should have at least 'self' parameter" + assert len(params) >= 1, f"get_buyers should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -51,9 +47,12 @@ def test_get_spaces_by_id_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_spaces_by_id" + ), f"Required parameter '{required_param}' missing from get_buyers" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "pagination_token", + "max_results", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -62,32 +61,47 @@ def test_get_spaces_by_id_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_spaces_by_id_return_annotation(self): - """Test that get_spaces_by_id has proper return type annotation.""" - method = getattr(SpacesClient, "get_spaces_by_id") + def test_get_buyers_return_annotation(self): + """Test that get_buyers has proper return type annotation.""" + method = getattr(SpacesClient, "get_buyers") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_spaces_by_id should have return type annotation" + ), f"Method get_buyers should have return type annotation" - def test_get_spaces_posts_exists(self): - """Test that get_spaces_posts method exists with correct signature.""" - # Check method exists - method = getattr(SpacesClient, "get_spaces_posts", None) + def test_get_buyers_pagination_params(self): + """Test that get_buyers has pagination parameters.""" + method = getattr(SpacesClient, "get_buyers") + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have pagination-related parameters + pagination_params = [ + "pagination_token", + "max_results", + "next_token", + "cursor", + "limit", + ] + has_pagination_param = any(param in params for param in pagination_params) assert ( - method is not None - ), f"Method get_spaces_posts does not exist on SpacesClient" + has_pagination_param + ), f"Paginated method get_buyers should have pagination parameters" + + + def test_get_by_id_exists(self): + """Test that get_by_id method exists with correct signature.""" + # Check method exists + method = getattr(SpacesClient, "get_by_id", None) + assert method is not None, f"Method get_by_id does not exist on SpacesClient" # Check method is callable - assert callable(method), f"get_spaces_posts is not callable" + assert callable(method), f"get_by_id is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_spaces_posts should have at least 'self' parameter" + assert len(params) >= 1, f"get_by_id should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -98,11 +112,9 @@ def test_get_spaces_posts_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_spaces_posts" + ), f"Required parameter '{required_param}' missing from get_by_id" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -111,45 +123,43 @@ def test_get_spaces_posts_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_spaces_posts_return_annotation(self): - """Test that get_spaces_posts has proper return type annotation.""" - method = getattr(SpacesClient, "get_spaces_posts") + def test_get_by_id_return_annotation(self): + """Test that get_by_id has proper return type annotation.""" + method = getattr(SpacesClient, "get_by_id") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_spaces_posts should have return type annotation" + ), f"Method get_by_id should have return type annotation" - def test_get_spaces_by_creator_ids_exists(self): - """Test that get_spaces_by_creator_ids method exists with correct signature.""" + def test_get_posts_exists(self): + """Test that get_posts method exists with correct signature.""" # Check method exists - method = getattr(SpacesClient, "get_spaces_by_creator_ids", None) - assert ( - method is not None - ), f"Method get_spaces_by_creator_ids does not exist on SpacesClient" + method = getattr(SpacesClient, "get_posts", None) + assert method is not None, f"Method get_posts does not exist on SpacesClient" # Check method is callable - assert callable(method), f"get_spaces_by_creator_ids is not callable" + assert callable(method), f"get_posts is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_spaces_by_creator_ids should have at least 'self' parameter" + assert len(params) >= 1, f"get_posts should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "user_ids", + "id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_spaces_by_creator_ids" + ), f"Required parameter '{required_param}' missing from get_posts" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "max_results", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -158,48 +168,41 @@ def test_get_spaces_by_creator_ids_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_spaces_by_creator_ids_return_annotation(self): - """Test that get_spaces_by_creator_ids has proper return type annotation.""" - method = getattr(SpacesClient, "get_spaces_by_creator_ids") + def test_get_posts_return_annotation(self): + """Test that get_posts has proper return type annotation.""" + method = getattr(SpacesClient, "get_posts") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_spaces_by_creator_ids should have return type annotation" + ), f"Method get_posts should have return type annotation" - def test_get_spaces_buyers_exists(self): - """Test that get_spaces_buyers method exists with correct signature.""" + def test_get_by_ids_exists(self): + """Test that get_by_ids method exists with correct signature.""" # Check method exists - method = getattr(SpacesClient, "get_spaces_buyers", None) - assert ( - method is not None - ), f"Method get_spaces_buyers does not exist on SpacesClient" + method = getattr(SpacesClient, "get_by_ids", None) + assert method is not None, f"Method get_by_ids does not exist on SpacesClient" # Check method is callable - assert callable(method), f"get_spaces_buyers is not callable" + assert callable(method), f"get_by_ids is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_spaces_buyers should have at least 'self' parameter" + assert len(params) >= 1, f"get_by_ids should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "id", + "ids", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_spaces_buyers" + ), f"Required parameter '{required_param}' missing from get_by_ids" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "pagination_token", - "max_results", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -208,64 +211,44 @@ def test_get_spaces_buyers_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_spaces_buyers_return_annotation(self): - """Test that get_spaces_buyers has proper return type annotation.""" - method = getattr(SpacesClient, "get_spaces_buyers") + def test_get_by_ids_return_annotation(self): + """Test that get_by_ids has proper return type annotation.""" + method = getattr(SpacesClient, "get_by_ids") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_spaces_buyers should have return type annotation" - - - def test_get_spaces_buyers_pagination_params(self): - """Test that get_spaces_buyers has pagination parameters.""" - method = getattr(SpacesClient, "get_spaces_buyers") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_spaces_buyers should have pagination parameters" + ), f"Method get_by_ids should have return type annotation" - def test_get_spaces_by_ids_exists(self): - """Test that get_spaces_by_ids method exists with correct signature.""" + def test_search_exists(self): + """Test that search method exists with correct signature.""" # Check method exists - method = getattr(SpacesClient, "get_spaces_by_ids", None) - assert ( - method is not None - ), f"Method get_spaces_by_ids does not exist on SpacesClient" + method = getattr(SpacesClient, "search", None) + assert method is not None, f"Method search does not exist on SpacesClient" # Check method is callable - assert callable(method), f"get_spaces_by_ids is not callable" + assert callable(method), f"search is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_spaces_by_ids should have at least 'self' parameter" + assert len(params) >= 1, f"search should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "ids", + "query", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_spaces_by_ids" + ), f"Required parameter '{required_param}' missing from search" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "state", + "max_results", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -274,46 +257,45 @@ def test_get_spaces_by_ids_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_spaces_by_ids_return_annotation(self): - """Test that get_spaces_by_ids has proper return type annotation.""" - method = getattr(SpacesClient, "get_spaces_by_ids") + def test_search_return_annotation(self): + """Test that search has proper return type annotation.""" + method = getattr(SpacesClient, "search") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_spaces_by_ids should have return type annotation" + ), f"Method search should have return type annotation" - def test_search_spaces_exists(self): - """Test that search_spaces method exists with correct signature.""" + def test_get_by_creator_ids_exists(self): + """Test that get_by_creator_ids method exists with correct signature.""" # Check method exists - method = getattr(SpacesClient, "search_spaces", None) + method = getattr(SpacesClient, "get_by_creator_ids", None) assert ( method is not None - ), f"Method search_spaces does not exist on SpacesClient" + ), f"Method get_by_creator_ids does not exist on SpacesClient" # Check method is callable - assert callable(method), f"search_spaces is not callable" + assert callable(method), f"get_by_creator_ids is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"search_spaces should have at least 'self' parameter" + assert ( + len(params) >= 1 + ), f"get_by_creator_ids should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "query", + "user_ids", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from search_spaces" + ), f"Required parameter '{required_param}' missing from get_by_creator_ids" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "state", - "max_results", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -322,25 +304,25 @@ def test_search_spaces_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_search_spaces_return_annotation(self): - """Test that search_spaces has proper return type annotation.""" - method = getattr(SpacesClient, "search_spaces") + def test_get_by_creator_ids_return_annotation(self): + """Test that get_by_creator_ids has proper return type annotation.""" + method = getattr(SpacesClient, "get_by_creator_ids") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method search_spaces should have return type annotation" + ), f"Method get_by_creator_ids should have return type annotation" def test_all_expected_methods_exist(self): """Test that all expected methods exist on the client.""" expected_methods = [ - "get_spaces_by_id", - "get_spaces_posts", - "get_spaces_by_creator_ids", - "get_spaces_buyers", - "get_spaces_by_ids", - "search_spaces", + "get_buyers", + "get_by_id", + "get_posts", + "get_by_ids", + "search", + "get_by_creator_ids", ] for expected_method in expected_methods: assert hasattr( diff --git a/xdk/python/tests/stream/test_contracts.py b/xdk/python/tests/stream/test_contracts.py index 527add40..d4692398 100644 --- a/xdk/python/tests/stream/test_contracts.py +++ b/xdk/python/tests/stream/test_contracts.py @@ -1,8 +1,8 @@ """ -Auto-generated contract tests for Stream client. +Auto-generated contract tests for {"class_name": "Stream", "display_name": "stream", "import_name": "stream", "original": ["stream"], "property_name": "stream"} client. This module contains tests that validate the request/response contracts -of the Stream client against the OpenAPI specification. +of the {"class_name": "Stream", "display_name": "stream", "import_name": "stream", "original": ["stream"], "property_name": "stream"} client against the OpenAPI specification. Generated automatically - do not edit manually. """ @@ -24,8 +24,8 @@ def setup_class(self): self.stream_client = getattr(self.client, "stream") - def test_stream_likes_firehose_request_structure(self): - """Test stream_likes_firehose request structure.""" + def test_likes_sample10_request_structure(self): + """Test likes_sample10 request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -42,7 +42,7 @@ def test_stream_likes_firehose_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.stream_client, "stream_likes_firehose") + method = getattr(self.stream_client, "likes_sample10") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -52,7 +52,7 @@ def test_stream_likes_firehose_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/likes/firehose/stream" + expected_path = "/2/likes/sample10/stream" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -61,12 +61,12 @@ def test_stream_likes_firehose_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for stream_likes_firehose: {e}") + pytest.fail(f"Contract test failed for likes_sample10: {e}") - def test_stream_likes_firehose_required_parameters(self): - """Test that stream_likes_firehose handles parameters correctly.""" - method = getattr(self.stream_client, "stream_likes_firehose") + def test_likes_sample10_required_parameters(self): + """Test that likes_sample10 handles parameters correctly.""" + method = getattr(self.stream_client, "likes_sample10") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -80,8 +80,8 @@ def test_stream_likes_firehose_required_parameters(self): method() - def test_stream_likes_firehose_response_structure(self): - """Test stream_likes_firehose response structure validation.""" + def test_likes_sample10_response_structure(self): + """Test likes_sample10 response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -97,7 +97,7 @@ def test_stream_likes_firehose_response_structure(self): kwargs["partition"] = 1 # Add request body if required # Call method and verify response structure - method = getattr(self.stream_client, "stream_likes_firehose") + method = getattr(self.stream_client, "likes_sample10") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -109,8 +109,8 @@ def test_stream_likes_firehose_response_structure(self): ) - def test_stream_likes_compliance_request_structure(self): - """Test stream_likes_compliance request structure.""" + def test_posts_sample_request_structure(self): + """Test posts_sample request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -126,7 +126,7 @@ def test_stream_likes_compliance_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.stream_client, "stream_likes_compliance") + method = getattr(self.stream_client, "posts_sample") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -136,7 +136,7 @@ def test_stream_likes_compliance_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/likes/compliance/stream" + expected_path = "/2/tweets/sample/stream" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -145,12 +145,12 @@ def test_stream_likes_compliance_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for stream_likes_compliance: {e}") + pytest.fail(f"Contract test failed for posts_sample: {e}") - def test_stream_likes_compliance_required_parameters(self): - """Test that stream_likes_compliance handles parameters correctly.""" - method = getattr(self.stream_client, "stream_likes_compliance") + def test_posts_sample_required_parameters(self): + """Test that posts_sample handles parameters correctly.""" + method = getattr(self.stream_client, "posts_sample") # No required parameters, method should be callable without args with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -164,8 +164,8 @@ def test_stream_likes_compliance_required_parameters(self): pytest.fail(f"Method with no required params should be callable: {e}") - def test_stream_likes_compliance_response_structure(self): - """Test stream_likes_compliance response structure validation.""" + def test_posts_sample_response_structure(self): + """Test posts_sample response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -180,7 +180,7 @@ def test_stream_likes_compliance_response_structure(self): kwargs = {} # Add request body if required # Call method and verify response structure - method = getattr(self.stream_client, "stream_likes_compliance") + method = getattr(self.stream_client, "posts_sample") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -192,8 +192,8 @@ def test_stream_likes_compliance_response_structure(self): ) - def test_stream_posts_firehose_pt_request_structure(self): - """Test stream_posts_firehose_pt request structure.""" + def test_get_rule_counts_request_structure(self): + """Test get_rule_counts request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -206,11 +206,10 @@ def test_stream_posts_firehose_pt_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["partition"] = 42 # Add request body if required # Call the method try: - method = getattr(self.stream_client, "stream_posts_firehose_pt") + method = getattr(self.stream_client, "get_rule_counts") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -220,7 +219,7 @@ def test_stream_posts_firehose_pt_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/tweets/firehose/stream/lang/pt" + expected_path = "/2/tweets/search/stream/rules/counts" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -229,27 +228,27 @@ def test_stream_posts_firehose_pt_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose_pt: {e}") + pytest.fail(f"Contract test failed for get_rule_counts: {e}") - def test_stream_posts_firehose_pt_required_parameters(self): - """Test that stream_posts_firehose_pt handles parameters correctly.""" - method = getattr(self.stream_client, "stream_posts_firehose_pt") - # Test with missing required parameters - mock the request to avoid network calls + def test_get_rule_counts_required_parameters(self): + """Test that get_rule_counts handles parameters correctly.""" + method = getattr(self.stream_client, "get_rule_counts") + # No required parameters, method should be callable without args with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") + mock_response.status_code = 200 + mock_response.json.return_value = {} + mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): + try: method() + except Exception as e: + pytest.fail(f"Method with no required params should be callable: {e}") - def test_stream_posts_firehose_pt_response_structure(self): - """Test stream_posts_firehose_pt response structure validation.""" + def test_get_rule_counts_response_structure(self): + """Test get_rule_counts response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -262,10 +261,9 @@ def test_stream_posts_firehose_pt_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["partition"] = 1 # Add request body if required # Call method and verify response structure - method = getattr(self.stream_client, "stream_posts_firehose_pt") + method = getattr(self.stream_client, "get_rule_counts") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -277,8 +275,8 @@ def test_stream_posts_firehose_pt_response_structure(self): ) - def test_stream_posts_compliance_request_structure(self): - """Test stream_posts_compliance request structure.""" + def test_posts_firehose_pt_request_structure(self): + """Test posts_firehose_pt request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -295,7 +293,7 @@ def test_stream_posts_compliance_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.stream_client, "stream_posts_compliance") + method = getattr(self.stream_client, "posts_firehose_pt") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -305,7 +303,7 @@ def test_stream_posts_compliance_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/tweets/compliance/stream" + expected_path = "/2/tweets/firehose/stream/lang/pt" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -314,12 +312,12 @@ def test_stream_posts_compliance_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_compliance: {e}") + pytest.fail(f"Contract test failed for posts_firehose_pt: {e}") - def test_stream_posts_compliance_required_parameters(self): - """Test that stream_posts_compliance handles parameters correctly.""" - method = getattr(self.stream_client, "stream_posts_compliance") + def test_posts_firehose_pt_required_parameters(self): + """Test that posts_firehose_pt handles parameters correctly.""" + method = getattr(self.stream_client, "posts_firehose_pt") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -333,8 +331,8 @@ def test_stream_posts_compliance_required_parameters(self): method() - def test_stream_posts_compliance_response_structure(self): - """Test stream_posts_compliance response structure validation.""" + def test_posts_firehose_pt_response_structure(self): + """Test posts_firehose_pt response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -350,7 +348,7 @@ def test_stream_posts_compliance_response_structure(self): kwargs["partition"] = 1 # Add request body if required # Call method and verify response structure - method = getattr(self.stream_client, "stream_posts_compliance") + method = getattr(self.stream_client, "posts_firehose_pt") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -362,8 +360,8 @@ def test_stream_posts_compliance_response_structure(self): ) - def test_stream_posts_firehose_ja_request_structure(self): - """Test stream_posts_firehose_ja request structure.""" + def test_labels_compliance_request_structure(self): + """Test labels_compliance request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -376,11 +374,10 @@ def test_stream_posts_firehose_ja_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["partition"] = 42 # Add request body if required # Call the method try: - method = getattr(self.stream_client, "stream_posts_firehose_ja") + method = getattr(self.stream_client, "labels_compliance") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -390,7 +387,7 @@ def test_stream_posts_firehose_ja_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/tweets/firehose/stream/lang/ja" + expected_path = "/2/tweets/label/stream" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -399,27 +396,27 @@ def test_stream_posts_firehose_ja_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose_ja: {e}") + pytest.fail(f"Contract test failed for labels_compliance: {e}") - def test_stream_posts_firehose_ja_required_parameters(self): - """Test that stream_posts_firehose_ja handles parameters correctly.""" - method = getattr(self.stream_client, "stream_posts_firehose_ja") - # Test with missing required parameters - mock the request to avoid network calls + def test_labels_compliance_required_parameters(self): + """Test that labels_compliance handles parameters correctly.""" + method = getattr(self.stream_client, "labels_compliance") + # No required parameters, method should be callable without args with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") + mock_response.status_code = 200 + mock_response.json.return_value = {} + mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): + try: method() + except Exception as e: + pytest.fail(f"Method with no required params should be callable: {e}") - def test_stream_posts_firehose_ja_response_structure(self): - """Test stream_posts_firehose_ja response structure validation.""" + def test_labels_compliance_response_structure(self): + """Test labels_compliance response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -432,10 +429,9 @@ def test_stream_posts_firehose_ja_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["partition"] = 1 # Add request body if required # Call method and verify response structure - method = getattr(self.stream_client, "stream_posts_firehose_ja") + method = getattr(self.stream_client, "labels_compliance") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -447,8 +443,8 @@ def test_stream_posts_firehose_ja_response_structure(self): ) - def test_stream_posts_firehose_en_request_structure(self): - """Test stream_posts_firehose_en request structure.""" + def test_likes_firehose_request_structure(self): + """Test likes_firehose request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -465,7 +461,7 @@ def test_stream_posts_firehose_en_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.stream_client, "stream_posts_firehose_en") + method = getattr(self.stream_client, "likes_firehose") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -475,7 +471,7 @@ def test_stream_posts_firehose_en_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/tweets/firehose/stream/lang/en" + expected_path = "/2/likes/firehose/stream" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -484,12 +480,12 @@ def test_stream_posts_firehose_en_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose_en: {e}") + pytest.fail(f"Contract test failed for likes_firehose: {e}") - def test_stream_posts_firehose_en_required_parameters(self): - """Test that stream_posts_firehose_en handles parameters correctly.""" - method = getattr(self.stream_client, "stream_posts_firehose_en") + def test_likes_firehose_required_parameters(self): + """Test that likes_firehose handles parameters correctly.""" + method = getattr(self.stream_client, "likes_firehose") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -503,8 +499,8 @@ def test_stream_posts_firehose_en_required_parameters(self): method() - def test_stream_posts_firehose_en_response_structure(self): - """Test stream_posts_firehose_en response structure validation.""" + def test_likes_firehose_response_structure(self): + """Test likes_firehose response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -520,7 +516,7 @@ def test_stream_posts_firehose_en_response_structure(self): kwargs["partition"] = 1 # Add request body if required # Call method and verify response structure - method = getattr(self.stream_client, "stream_posts_firehose_en") + method = getattr(self.stream_client, "likes_firehose") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -532,8 +528,8 @@ def test_stream_posts_firehose_en_response_structure(self): ) - def test_stream_posts_sample_request_structure(self): - """Test stream_posts_sample request structure.""" + def test_posts_request_structure(self): + """Test posts request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -549,7 +545,7 @@ def test_stream_posts_sample_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.stream_client, "stream_posts_sample") + method = getattr(self.stream_client, "posts") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -559,7 +555,7 @@ def test_stream_posts_sample_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/tweets/sample/stream" + expected_path = "/2/tweets/search/stream" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -568,12 +564,12 @@ def test_stream_posts_sample_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_sample: {e}") + pytest.fail(f"Contract test failed for posts: {e}") - def test_stream_posts_sample_required_parameters(self): - """Test that stream_posts_sample handles parameters correctly.""" - method = getattr(self.stream_client, "stream_posts_sample") + def test_posts_required_parameters(self): + """Test that posts handles parameters correctly.""" + method = getattr(self.stream_client, "posts") # No required parameters, method should be callable without args with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -587,8 +583,8 @@ def test_stream_posts_sample_required_parameters(self): pytest.fail(f"Method with no required params should be callable: {e}") - def test_stream_posts_sample_response_structure(self): - """Test stream_posts_sample response structure validation.""" + def test_posts_response_structure(self): + """Test posts response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -603,7 +599,7 @@ def test_stream_posts_sample_response_structure(self): kwargs = {} # Add request body if required # Call method and verify response structure - method = getattr(self.stream_client, "stream_posts_sample") + method = getattr(self.stream_client, "posts") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -615,8 +611,8 @@ def test_stream_posts_sample_response_structure(self): ) - def test_get_rules_request_structure(self): - """Test get_rules request structure.""" + def test_posts_firehose_request_structure(self): + """Test posts_firehose request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -629,10 +625,11 @@ def test_get_rules_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters + kwargs["partition"] = 42 # Add request body if required # Call the method try: - method = getattr(self.stream_client, "get_rules") + method = getattr(self.stream_client, "posts_firehose") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -642,7 +639,7 @@ def test_get_rules_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/tweets/search/stream/rules" + expected_path = "/2/tweets/firehose/stream" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -651,27 +648,27 @@ def test_get_rules_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_rules: {e}") + pytest.fail(f"Contract test failed for posts_firehose: {e}") - def test_get_rules_required_parameters(self): - """Test that get_rules handles parameters correctly.""" - method = getattr(self.stream_client, "get_rules") - # No required parameters, method should be callable without args + def test_posts_firehose_required_parameters(self): + """Test that posts_firehose handles parameters correctly.""" + method = getattr(self.stream_client, "posts_firehose") + # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: + # Mock a 400 response (typical for missing required parameters) mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None + mock_response.status_code = 400 + mock_response.json.return_value = {"error": "Missing required parameters"} + mock_response.raise_for_status.side_effect = Exception("Bad Request") mock_session.get.return_value = mock_response - try: + # Call without required parameters should either raise locally or via server response + with pytest.raises((TypeError, ValueError, Exception)): method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - def test_get_rules_response_structure(self): - """Test get_rules response structure validation.""" + def test_posts_firehose_response_structure(self): + """Test posts_firehose response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -684,9 +681,10 @@ def test_get_rules_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} + kwargs["partition"] = 1 # Add request body if required # Call method and verify response structure - method = getattr(self.stream_client, "get_rules") + method = getattr(self.stream_client, "posts_firehose") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -698,8 +696,8 @@ def test_get_rules_response_structure(self): ) - def test_update_rules_request_structure(self): - """Test update_rules request structure.""" + def test_posts_compliance_request_structure(self): + """Test posts_compliance request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -708,28 +706,25 @@ def test_update_rules_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters + kwargs["partition"] = 42 # Add request body if required - # Import and create proper request model instance - from xdk.stream.models import UpdateRulesRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = UpdateRulesRequest() # Call the method try: - method = getattr(self.stream_client, "update_rules") + method = getattr(self.stream_client, "posts_compliance") result = method(**kwargs) # Verify the request was made - mock_session.post.assert_called_once() + mock_session.get.assert_called_once() # Verify request structure - call_args = mock_session.post.call_args + call_args = mock_session.get.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/tweets/search/stream/rules" + expected_path = "/2/tweets/compliance/stream" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -738,12 +733,12 @@ def test_update_rules_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for update_rules: {e}") + pytest.fail(f"Contract test failed for posts_compliance: {e}") - def test_update_rules_required_parameters(self): - """Test that update_rules handles parameters correctly.""" - method = getattr(self.stream_client, "update_rules") + def test_posts_compliance_required_parameters(self): + """Test that posts_compliance handles parameters correctly.""" + method = getattr(self.stream_client, "posts_compliance") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -751,14 +746,14 @@ def test_update_rules_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_update_rules_response_structure(self): - """Test update_rules response structure validation.""" + def test_posts_compliance_response_structure(self): + """Test posts_compliance response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -768,16 +763,13 @@ def test_update_rules_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} + kwargs["partition"] = 1 # Add request body if required - # Import and create proper request model instance - from xdk.stream.models import UpdateRulesRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = UpdateRulesRequest() # Call method and verify response structure - method = getattr(self.stream_client, "update_rules") + method = getattr(self.stream_client, "posts_compliance") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -789,8 +781,8 @@ def test_update_rules_response_structure(self): ) - def test_stream_users_compliance_request_structure(self): - """Test stream_users_compliance request structure.""" + def test_get_rules_request_structure(self): + """Test get_rules request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -803,11 +795,10 @@ def test_stream_users_compliance_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["partition"] = 42 # Add request body if required # Call the method try: - method = getattr(self.stream_client, "stream_users_compliance") + method = getattr(self.stream_client, "get_rules") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -817,7 +808,7 @@ def test_stream_users_compliance_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/compliance/stream" + expected_path = "/2/tweets/search/stream/rules" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -826,27 +817,27 @@ def test_stream_users_compliance_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for stream_users_compliance: {e}") + pytest.fail(f"Contract test failed for get_rules: {e}") - def test_stream_users_compliance_required_parameters(self): - """Test that stream_users_compliance handles parameters correctly.""" - method = getattr(self.stream_client, "stream_users_compliance") - # Test with missing required parameters - mock the request to avoid network calls + def test_get_rules_required_parameters(self): + """Test that get_rules handles parameters correctly.""" + method = getattr(self.stream_client, "get_rules") + # No required parameters, method should be callable without args with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") + mock_response.status_code = 200 + mock_response.json.return_value = {} + mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): + try: method() + except Exception as e: + pytest.fail(f"Method with no required params should be callable: {e}") - def test_stream_users_compliance_response_structure(self): - """Test stream_users_compliance response structure validation.""" + def test_get_rules_response_structure(self): + """Test get_rules response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -859,10 +850,9 @@ def test_stream_users_compliance_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["partition"] = 1 # Add request body if required # Call method and verify response structure - method = getattr(self.stream_client, "stream_users_compliance") + method = getattr(self.stream_client, "get_rules") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -874,8 +864,8 @@ def test_stream_users_compliance_response_structure(self): ) - def test_stream_posts_firehose_ko_request_structure(self): - """Test stream_posts_firehose_ko request structure.""" + def test_update_rules_request_structure(self): + """Test update_rules request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -884,25 +874,28 @@ def test_stream_posts_firehose_ko_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["partition"] = 42 # Add request body if required + # Import and create proper request model instance + from xdk.stream.models import UpdateRulesRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = UpdateRulesRequest() # Call the method try: - method = getattr(self.stream_client, "stream_posts_firehose_ko") + method = getattr(self.stream_client, "update_rules") result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.post.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.post.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/tweets/firehose/stream/lang/ko" + expected_path = "/2/tweets/search/stream/rules" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -911,12 +904,12 @@ def test_stream_posts_firehose_ko_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose_ko: {e}") + pytest.fail(f"Contract test failed for update_rules: {e}") - def test_stream_posts_firehose_ko_required_parameters(self): - """Test that stream_posts_firehose_ko handles parameters correctly.""" - method = getattr(self.stream_client, "stream_posts_firehose_ko") + def test_update_rules_required_parameters(self): + """Test that update_rules handles parameters correctly.""" + method = getattr(self.stream_client, "update_rules") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -924,14 +917,14 @@ def test_stream_posts_firehose_ko_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_stream_posts_firehose_ko_response_structure(self): - """Test stream_posts_firehose_ko response structure validation.""" + def test_update_rules_response_structure(self): + """Test update_rules response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -941,13 +934,16 @@ def test_stream_posts_firehose_ko_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["partition"] = 1 # Add request body if required + # Import and create proper request model instance + from xdk.stream.models import UpdateRulesRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = UpdateRulesRequest() # Call method and verify response structure - method = getattr(self.stream_client, "stream_posts_firehose_ko") + method = getattr(self.stream_client, "update_rules") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -959,8 +955,8 @@ def test_stream_posts_firehose_ko_response_structure(self): ) - def test_get_rule_counts_request_structure(self): - """Test get_rule_counts request structure.""" + def test_likes_compliance_request_structure(self): + """Test likes_compliance request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -976,7 +972,7 @@ def test_get_rule_counts_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.stream_client, "get_rule_counts") + method = getattr(self.stream_client, "likes_compliance") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -986,7 +982,7 @@ def test_get_rule_counts_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/tweets/search/stream/rules/counts" + expected_path = "/2/likes/compliance/stream" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -995,12 +991,12 @@ def test_get_rule_counts_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_rule_counts: {e}") + pytest.fail(f"Contract test failed for likes_compliance: {e}") - def test_get_rule_counts_required_parameters(self): - """Test that get_rule_counts handles parameters correctly.""" - method = getattr(self.stream_client, "get_rule_counts") + def test_likes_compliance_required_parameters(self): + """Test that likes_compliance handles parameters correctly.""" + method = getattr(self.stream_client, "likes_compliance") # No required parameters, method should be callable without args with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1014,8 +1010,8 @@ def test_get_rule_counts_required_parameters(self): pytest.fail(f"Method with no required params should be callable: {e}") - def test_get_rule_counts_response_structure(self): - """Test get_rule_counts response structure validation.""" + def test_likes_compliance_response_structure(self): + """Test likes_compliance response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1030,7 +1026,7 @@ def test_get_rule_counts_response_structure(self): kwargs = {} # Add request body if required # Call method and verify response structure - method = getattr(self.stream_client, "get_rule_counts") + method = getattr(self.stream_client, "likes_compliance") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1042,8 +1038,8 @@ def test_get_rule_counts_response_structure(self): ) - def test_stream_posts_firehose_request_structure(self): - """Test stream_posts_firehose request structure.""" + def test_users_compliance_request_structure(self): + """Test users_compliance request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1060,7 +1056,7 @@ def test_stream_posts_firehose_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.stream_client, "stream_posts_firehose") + method = getattr(self.stream_client, "users_compliance") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -1070,7 +1066,7 @@ def test_stream_posts_firehose_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/tweets/firehose/stream" + expected_path = "/2/users/compliance/stream" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1079,12 +1075,12 @@ def test_stream_posts_firehose_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose: {e}") + pytest.fail(f"Contract test failed for users_compliance: {e}") - def test_stream_posts_firehose_required_parameters(self): - """Test that stream_posts_firehose handles parameters correctly.""" - method = getattr(self.stream_client, "stream_posts_firehose") + def test_users_compliance_required_parameters(self): + """Test that users_compliance handles parameters correctly.""" + method = getattr(self.stream_client, "users_compliance") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1098,8 +1094,8 @@ def test_stream_posts_firehose_required_parameters(self): method() - def test_stream_posts_firehose_response_structure(self): - """Test stream_posts_firehose response structure validation.""" + def test_users_compliance_response_structure(self): + """Test users_compliance response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1115,7 +1111,7 @@ def test_stream_posts_firehose_response_structure(self): kwargs["partition"] = 1 # Add request body if required # Call method and verify response structure - method = getattr(self.stream_client, "stream_posts_firehose") + method = getattr(self.stream_client, "users_compliance") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1127,8 +1123,8 @@ def test_stream_posts_firehose_response_structure(self): ) - def test_stream_posts_sample10_request_structure(self): - """Test stream_posts_sample10 request structure.""" + def test_posts_firehose_en_request_structure(self): + """Test posts_firehose_en request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1145,7 +1141,7 @@ def test_stream_posts_sample10_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.stream_client, "stream_posts_sample10") + method = getattr(self.stream_client, "posts_firehose_en") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -1155,7 +1151,7 @@ def test_stream_posts_sample10_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/tweets/sample10/stream" + expected_path = "/2/tweets/firehose/stream/lang/en" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1164,12 +1160,12 @@ def test_stream_posts_sample10_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_sample10: {e}") + pytest.fail(f"Contract test failed for posts_firehose_en: {e}") - def test_stream_posts_sample10_required_parameters(self): - """Test that stream_posts_sample10 handles parameters correctly.""" - method = getattr(self.stream_client, "stream_posts_sample10") + def test_posts_firehose_en_required_parameters(self): + """Test that posts_firehose_en handles parameters correctly.""" + method = getattr(self.stream_client, "posts_firehose_en") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1183,8 +1179,8 @@ def test_stream_posts_sample10_required_parameters(self): method() - def test_stream_posts_sample10_response_structure(self): - """Test stream_posts_sample10 response structure validation.""" + def test_posts_firehose_en_response_structure(self): + """Test posts_firehose_en response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1200,7 +1196,7 @@ def test_stream_posts_sample10_response_structure(self): kwargs["partition"] = 1 # Add request body if required # Call method and verify response structure - method = getattr(self.stream_client, "stream_posts_sample10") + method = getattr(self.stream_client, "posts_firehose_en") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1212,8 +1208,8 @@ def test_stream_posts_sample10_response_structure(self): ) - def test_stream_likes_sample10_request_structure(self): - """Test stream_likes_sample10 request structure.""" + def test_posts_firehose_ja_request_structure(self): + """Test posts_firehose_ja request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1230,7 +1226,7 @@ def test_stream_likes_sample10_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.stream_client, "stream_likes_sample10") + method = getattr(self.stream_client, "posts_firehose_ja") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -1240,7 +1236,7 @@ def test_stream_likes_sample10_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/likes/sample10/stream" + expected_path = "/2/tweets/firehose/stream/lang/ja" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1249,12 +1245,12 @@ def test_stream_likes_sample10_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for stream_likes_sample10: {e}") + pytest.fail(f"Contract test failed for posts_firehose_ja: {e}") - def test_stream_likes_sample10_required_parameters(self): - """Test that stream_likes_sample10 handles parameters correctly.""" - method = getattr(self.stream_client, "stream_likes_sample10") + def test_posts_firehose_ja_required_parameters(self): + """Test that posts_firehose_ja handles parameters correctly.""" + method = getattr(self.stream_client, "posts_firehose_ja") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1268,8 +1264,8 @@ def test_stream_likes_sample10_required_parameters(self): method() - def test_stream_likes_sample10_response_structure(self): - """Test stream_likes_sample10 response structure validation.""" + def test_posts_firehose_ja_response_structure(self): + """Test posts_firehose_ja response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1285,7 +1281,7 @@ def test_stream_likes_sample10_response_structure(self): kwargs["partition"] = 1 # Add request body if required # Call method and verify response structure - method = getattr(self.stream_client, "stream_likes_sample10") + method = getattr(self.stream_client, "posts_firehose_ja") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1297,8 +1293,8 @@ def test_stream_likes_sample10_response_structure(self): ) - def test_stream_labels_compliance_request_structure(self): - """Test stream_labels_compliance request structure.""" + def test_posts_firehose_ko_request_structure(self): + """Test posts_firehose_ko request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1311,10 +1307,11 @@ def test_stream_labels_compliance_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters + kwargs["partition"] = 42 # Add request body if required # Call the method try: - method = getattr(self.stream_client, "stream_labels_compliance") + method = getattr(self.stream_client, "posts_firehose_ko") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -1324,7 +1321,7 @@ def test_stream_labels_compliance_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/tweets/label/stream" + expected_path = "/2/tweets/firehose/stream/lang/ko" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1333,27 +1330,27 @@ def test_stream_labels_compliance_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for stream_labels_compliance: {e}") + pytest.fail(f"Contract test failed for posts_firehose_ko: {e}") - def test_stream_labels_compliance_required_parameters(self): - """Test that stream_labels_compliance handles parameters correctly.""" - method = getattr(self.stream_client, "stream_labels_compliance") - # No required parameters, method should be callable without args + def test_posts_firehose_ko_required_parameters(self): + """Test that posts_firehose_ko handles parameters correctly.""" + method = getattr(self.stream_client, "posts_firehose_ko") + # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: + # Mock a 400 response (typical for missing required parameters) mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None + mock_response.status_code = 400 + mock_response.json.return_value = {"error": "Missing required parameters"} + mock_response.raise_for_status.side_effect = Exception("Bad Request") mock_session.get.return_value = mock_response - try: + # Call without required parameters should either raise locally or via server response + with pytest.raises((TypeError, ValueError, Exception)): method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - def test_stream_labels_compliance_response_structure(self): - """Test stream_labels_compliance response structure validation.""" + def test_posts_firehose_ko_response_structure(self): + """Test posts_firehose_ko response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1366,9 +1363,10 @@ def test_stream_labels_compliance_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} + kwargs["partition"] = 1 # Add request body if required # Call method and verify response structure - method = getattr(self.stream_client, "stream_labels_compliance") + method = getattr(self.stream_client, "posts_firehose_ko") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1380,8 +1378,8 @@ def test_stream_labels_compliance_response_structure(self): ) - def test_stream_posts_request_structure(self): - """Test stream_posts request structure.""" + def test_posts_sample10_request_structure(self): + """Test posts_sample10 request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1394,10 +1392,11 @@ def test_stream_posts_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters + kwargs["partition"] = 42 # Add request body if required # Call the method try: - method = getattr(self.stream_client, "stream_posts") + method = getattr(self.stream_client, "posts_sample10") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -1407,7 +1406,7 @@ def test_stream_posts_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/tweets/search/stream" + expected_path = "/2/tweets/sample10/stream" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1416,27 +1415,27 @@ def test_stream_posts_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for stream_posts: {e}") + pytest.fail(f"Contract test failed for posts_sample10: {e}") - def test_stream_posts_required_parameters(self): - """Test that stream_posts handles parameters correctly.""" - method = getattr(self.stream_client, "stream_posts") - # No required parameters, method should be callable without args + def test_posts_sample10_required_parameters(self): + """Test that posts_sample10 handles parameters correctly.""" + method = getattr(self.stream_client, "posts_sample10") + # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: + # Mock a 400 response (typical for missing required parameters) mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None + mock_response.status_code = 400 + mock_response.json.return_value = {"error": "Missing required parameters"} + mock_response.raise_for_status.side_effect = Exception("Bad Request") mock_session.get.return_value = mock_response - try: + # Call without required parameters should either raise locally or via server response + with pytest.raises((TypeError, ValueError, Exception)): method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - def test_stream_posts_response_structure(self): - """Test stream_posts response structure validation.""" + def test_posts_sample10_response_structure(self): + """Test posts_sample10 response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1449,9 +1448,10 @@ def test_stream_posts_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} + kwargs["partition"] = 1 # Add request body if required # Call method and verify response structure - method = getattr(self.stream_client, "stream_posts") + method = getattr(self.stream_client, "posts_sample10") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed diff --git a/xdk/python/tests/stream/test_generic.py b/xdk/python/tests/stream/test_generic.py index 867e3771..42c03169 100644 --- a/xdk/python/tests/stream/test_generic.py +++ b/xdk/python/tests/stream/test_generic.py @@ -1,5 +1,5 @@ """ -Auto-generated generic tests for Stream client. +Auto-generated generic tests for {"class_name": "Stream", "display_name": "stream", "import_name": "stream", "original": ["stream"], "property_name": "stream"} client. This module contains general tests that validate the overall client functionality, imports, and error handling that don't need to be diff --git a/xdk/python/tests/stream/test_pagination.py b/xdk/python/tests/stream/test_pagination.py index e3bde7c4..c014e614 100644 --- a/xdk/python/tests/stream/test_pagination.py +++ b/xdk/python/tests/stream/test_pagination.py @@ -1,5 +1,5 @@ """ -Auto-generated pagination tests for Stream client. +Auto-generated pagination tests for {"class_name": "Stream", "display_name": "stream", "import_name": "stream", "original": ["stream"], "property_name": "stream"} client. This module contains tests that validate pagination functionality using the Cursor class for methods that support pagination. @@ -32,7 +32,7 @@ def test_get_rules_cursor_creation(self): assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method getRules should support pagination") + pytest.fail(f"Method get_rules should support pagination") def test_get_rules_cursor_pages(self): diff --git a/xdk/python/tests/stream/test_structure.py b/xdk/python/tests/stream/test_structure.py index 5c54a570..9a494a0d 100644 --- a/xdk/python/tests/stream/test_structure.py +++ b/xdk/python/tests/stream/test_structure.py @@ -1,8 +1,8 @@ """ -Auto-generated structural tests for Stream client. +Auto-generated structural tests for {"class_name": "Stream", "display_name": "stream", "import_name": "stream", "original": ["stream"], "property_name": "stream"} client. This module contains tests that validate the structure and API surface -of the Stream client. These tests ensure that all expected methods +of the {"class_name": "Stream", "display_name": "stream", "import_name": "stream", "original": ["stream"], "property_name": "stream"} client. These tests ensure that all expected methods exist and have the correct signatures. Generated automatically - do not edit manually. @@ -25,22 +25,20 @@ def setup_class(self): self.stream_client = getattr(self.client, "stream") - def test_stream_likes_firehose_exists(self): - """Test that stream_likes_firehose method exists with correct signature.""" + def test_likes_sample10_exists(self): + """Test that likes_sample10 method exists with correct signature.""" # Check method exists - method = getattr(StreamClient, "stream_likes_firehose", None) + method = getattr(StreamClient, "likes_sample10", None) assert ( method is not None - ), f"Method stream_likes_firehose does not exist on StreamClient" + ), f"Method likes_sample10 does not exist on StreamClient" # Check method is callable - assert callable(method), f"stream_likes_firehose is not callable" + assert callable(method), f"likes_sample10 is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_likes_firehose should have at least 'self' parameter" + assert len(params) >= 1, f"likes_sample10 should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -51,7 +49,7 @@ def test_stream_likes_firehose_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from stream_likes_firehose" + ), f"Required parameter '{required_param}' missing from likes_sample10" # Check optional parameters have defaults (excluding 'self') optional_params = [ "backfill_minutes", @@ -66,32 +64,75 @@ def test_stream_likes_firehose_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_stream_likes_firehose_return_annotation(self): - """Test that stream_likes_firehose has proper return type annotation.""" - method = getattr(StreamClient, "stream_likes_firehose") + def test_likes_sample10_return_annotation(self): + """Test that likes_sample10 has proper return type annotation.""" + method = getattr(StreamClient, "likes_sample10") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_likes_firehose should have return type annotation" + ), f"Method likes_sample10 should have return type annotation" - def test_stream_likes_compliance_exists(self): - """Test that stream_likes_compliance method exists with correct signature.""" + def test_posts_sample_exists(self): + """Test that posts_sample method exists with correct signature.""" # Check method exists - method = getattr(StreamClient, "stream_likes_compliance", None) + method = getattr(StreamClient, "posts_sample", None) + assert method is not None, f"Method posts_sample does not exist on StreamClient" + # Check method is callable + assert callable(method), f"posts_sample is not callable" + # Check method signature + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have 'self' as first parameter + assert len(params) >= 1, f"posts_sample should have at least 'self' parameter" + assert ( + params[0] == "self" + ), f"First parameter should be 'self', got '{params[0]}'" + # Check required parameters exist (excluding 'self') + required_params = [] + for required_param in required_params: + assert ( + required_param in params + ), f"Required parameter '{required_param}' missing from posts_sample" + # Check optional parameters have defaults (excluding 'self') + optional_params = [ + "backfill_minutes", + ] + for optional_param in optional_params: + if optional_param in params: + param_obj = sig.parameters[optional_param] + assert ( + param_obj.default is not inspect.Parameter.empty + ), f"Optional parameter '{optional_param}' should have a default value" + + + def test_posts_sample_return_annotation(self): + """Test that posts_sample has proper return type annotation.""" + method = getattr(StreamClient, "posts_sample") + sig = inspect.signature(method) + # Check return annotation exists + assert ( + sig.return_annotation is not inspect.Signature.empty + ), f"Method posts_sample should have return type annotation" + + + def test_get_rule_counts_exists(self): + """Test that get_rule_counts method exists with correct signature.""" + # Check method exists + method = getattr(StreamClient, "get_rule_counts", None) assert ( method is not None - ), f"Method stream_likes_compliance does not exist on StreamClient" + ), f"Method get_rule_counts does not exist on StreamClient" # Check method is callable - assert callable(method), f"stream_likes_compliance is not callable" + assert callable(method), f"get_rule_counts is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"stream_likes_compliance should have at least 'self' parameter" + ), f"get_rule_counts should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -100,13 +141,9 @@ def test_stream_likes_compliance_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from stream_likes_compliance" + ), f"Required parameter '{required_param}' missing from get_rule_counts" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -115,32 +152,32 @@ def test_stream_likes_compliance_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_stream_likes_compliance_return_annotation(self): - """Test that stream_likes_compliance has proper return type annotation.""" - method = getattr(StreamClient, "stream_likes_compliance") + def test_get_rule_counts_return_annotation(self): + """Test that get_rule_counts has proper return type annotation.""" + method = getattr(StreamClient, "get_rule_counts") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_likes_compliance should have return type annotation" + ), f"Method get_rule_counts should have return type annotation" - def test_stream_posts_firehose_pt_exists(self): - """Test that stream_posts_firehose_pt method exists with correct signature.""" + def test_posts_firehose_pt_exists(self): + """Test that posts_firehose_pt method exists with correct signature.""" # Check method exists - method = getattr(StreamClient, "stream_posts_firehose_pt", None) + method = getattr(StreamClient, "posts_firehose_pt", None) assert ( method is not None - ), f"Method stream_posts_firehose_pt does not exist on StreamClient" + ), f"Method posts_firehose_pt does not exist on StreamClient" # Check method is callable - assert callable(method), f"stream_posts_firehose_pt is not callable" + assert callable(method), f"posts_firehose_pt is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"stream_posts_firehose_pt should have at least 'self' parameter" + ), f"posts_firehose_pt should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -151,7 +188,7 @@ def test_stream_posts_firehose_pt_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose_pt" + ), f"Required parameter '{required_param}' missing from posts_firehose_pt" # Check optional parameters have defaults (excluding 'self') optional_params = [ "backfill_minutes", @@ -166,43 +203,41 @@ def test_stream_posts_firehose_pt_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_stream_posts_firehose_pt_return_annotation(self): - """Test that stream_posts_firehose_pt has proper return type annotation.""" - method = getattr(StreamClient, "stream_posts_firehose_pt") + def test_posts_firehose_pt_return_annotation(self): + """Test that posts_firehose_pt has proper return type annotation.""" + method = getattr(StreamClient, "posts_firehose_pt") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose_pt should have return type annotation" + ), f"Method posts_firehose_pt should have return type annotation" - def test_stream_posts_compliance_exists(self): - """Test that stream_posts_compliance method exists with correct signature.""" + def test_labels_compliance_exists(self): + """Test that labels_compliance method exists with correct signature.""" # Check method exists - method = getattr(StreamClient, "stream_posts_compliance", None) + method = getattr(StreamClient, "labels_compliance", None) assert ( method is not None - ), f"Method stream_posts_compliance does not exist on StreamClient" + ), f"Method labels_compliance does not exist on StreamClient" # Check method is callable - assert callable(method), f"stream_posts_compliance is not callable" + assert callable(method), f"labels_compliance is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"stream_posts_compliance should have at least 'self' parameter" + ), f"labels_compliance should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] + required_params = [] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_compliance" + ), f"Required parameter '{required_param}' missing from labels_compliance" # Check optional parameters have defaults (excluding 'self') optional_params = [ "backfill_minutes", @@ -217,32 +252,30 @@ def test_stream_posts_compliance_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_stream_posts_compliance_return_annotation(self): - """Test that stream_posts_compliance has proper return type annotation.""" - method = getattr(StreamClient, "stream_posts_compliance") + def test_labels_compliance_return_annotation(self): + """Test that labels_compliance has proper return type annotation.""" + method = getattr(StreamClient, "labels_compliance") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_compliance should have return type annotation" + ), f"Method labels_compliance should have return type annotation" - def test_stream_posts_firehose_ja_exists(self): - """Test that stream_posts_firehose_ja method exists with correct signature.""" + def test_likes_firehose_exists(self): + """Test that likes_firehose method exists with correct signature.""" # Check method exists - method = getattr(StreamClient, "stream_posts_firehose_ja", None) + method = getattr(StreamClient, "likes_firehose", None) assert ( method is not None - ), f"Method stream_posts_firehose_ja does not exist on StreamClient" + ), f"Method likes_firehose does not exist on StreamClient" # Check method is callable - assert callable(method), f"stream_posts_firehose_ja is not callable" + assert callable(method), f"likes_firehose is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_firehose_ja should have at least 'self' parameter" + assert len(params) >= 1, f"likes_firehose should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -253,7 +286,7 @@ def test_stream_posts_firehose_ja_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose_ja" + ), f"Required parameter '{required_param}' missing from likes_firehose" # Check optional parameters have defaults (excluding 'self') optional_params = [ "backfill_minutes", @@ -268,32 +301,75 @@ def test_stream_posts_firehose_ja_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_stream_posts_firehose_ja_return_annotation(self): - """Test that stream_posts_firehose_ja has proper return type annotation.""" - method = getattr(StreamClient, "stream_posts_firehose_ja") + def test_likes_firehose_return_annotation(self): + """Test that likes_firehose has proper return type annotation.""" + method = getattr(StreamClient, "likes_firehose") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose_ja should have return type annotation" + ), f"Method likes_firehose should have return type annotation" - def test_stream_posts_firehose_en_exists(self): - """Test that stream_posts_firehose_en method exists with correct signature.""" + def test_posts_exists(self): + """Test that posts method exists with correct signature.""" # Check method exists - method = getattr(StreamClient, "stream_posts_firehose_en", None) + method = getattr(StreamClient, "posts", None) + assert method is not None, f"Method posts does not exist on StreamClient" + # Check method is callable + assert callable(method), f"posts is not callable" + # Check method signature + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have 'self' as first parameter + assert len(params) >= 1, f"posts should have at least 'self' parameter" + assert ( + params[0] == "self" + ), f"First parameter should be 'self', got '{params[0]}'" + # Check required parameters exist (excluding 'self') + required_params = [] + for required_param in required_params: + assert ( + required_param in params + ), f"Required parameter '{required_param}' missing from posts" + # Check optional parameters have defaults (excluding 'self') + optional_params = [ + "backfill_minutes", + "start_time", + "end_time", + ] + for optional_param in optional_params: + if optional_param in params: + param_obj = sig.parameters[optional_param] + assert ( + param_obj.default is not inspect.Parameter.empty + ), f"Optional parameter '{optional_param}' should have a default value" + + + def test_posts_return_annotation(self): + """Test that posts has proper return type annotation.""" + method = getattr(StreamClient, "posts") + sig = inspect.signature(method) + # Check return annotation exists + assert ( + sig.return_annotation is not inspect.Signature.empty + ), f"Method posts should have return type annotation" + + + def test_posts_firehose_exists(self): + """Test that posts_firehose method exists with correct signature.""" + # Check method exists + method = getattr(StreamClient, "posts_firehose", None) assert ( method is not None - ), f"Method stream_posts_firehose_en does not exist on StreamClient" + ), f"Method posts_firehose does not exist on StreamClient" # Check method is callable - assert callable(method), f"stream_posts_firehose_en is not callable" + assert callable(method), f"posts_firehose is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_firehose_en should have at least 'self' parameter" + assert len(params) >= 1, f"posts_firehose should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -304,7 +380,7 @@ def test_stream_posts_firehose_en_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose_en" + ), f"Required parameter '{required_param}' missing from posts_firehose" # Check optional parameters have defaults (excluding 'self') optional_params = [ "backfill_minutes", @@ -319,44 +395,48 @@ def test_stream_posts_firehose_en_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_stream_posts_firehose_en_return_annotation(self): - """Test that stream_posts_firehose_en has proper return type annotation.""" - method = getattr(StreamClient, "stream_posts_firehose_en") + def test_posts_firehose_return_annotation(self): + """Test that posts_firehose has proper return type annotation.""" + method = getattr(StreamClient, "posts_firehose") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose_en should have return type annotation" + ), f"Method posts_firehose should have return type annotation" - def test_stream_posts_sample_exists(self): - """Test that stream_posts_sample method exists with correct signature.""" + def test_posts_compliance_exists(self): + """Test that posts_compliance method exists with correct signature.""" # Check method exists - method = getattr(StreamClient, "stream_posts_sample", None) + method = getattr(StreamClient, "posts_compliance", None) assert ( method is not None - ), f"Method stream_posts_sample does not exist on StreamClient" + ), f"Method posts_compliance does not exist on StreamClient" # Check method is callable - assert callable(method), f"stream_posts_sample is not callable" + assert callable(method), f"posts_compliance is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"stream_posts_sample should have at least 'self' parameter" + ), f"posts_compliance should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [] + required_params = [ + "partition", + ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_sample" + ), f"Required parameter '{required_param}' missing from posts_compliance" # Check optional parameters have defaults (excluding 'self') optional_params = [ "backfill_minutes", + "start_time", + "end_time", ] for optional_param in optional_params: if optional_param in params: @@ -366,14 +446,14 @@ def test_stream_posts_sample_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_stream_posts_sample_return_annotation(self): - """Test that stream_posts_sample has proper return type annotation.""" - method = getattr(StreamClient, "stream_posts_sample") + def test_posts_compliance_return_annotation(self): + """Test that posts_compliance has proper return type annotation.""" + method = getattr(StreamClient, "posts_compliance") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_sample should have return type annotation" + ), f"Method posts_compliance should have return type annotation" def test_get_rules_exists(self): @@ -484,33 +564,31 @@ def test_update_rules_return_annotation(self): ), f"Method update_rules should have return type annotation" - def test_stream_users_compliance_exists(self): - """Test that stream_users_compliance method exists with correct signature.""" + def test_likes_compliance_exists(self): + """Test that likes_compliance method exists with correct signature.""" # Check method exists - method = getattr(StreamClient, "stream_users_compliance", None) + method = getattr(StreamClient, "likes_compliance", None) assert ( method is not None - ), f"Method stream_users_compliance does not exist on StreamClient" + ), f"Method likes_compliance does not exist on StreamClient" # Check method is callable - assert callable(method), f"stream_users_compliance is not callable" + assert callable(method), f"likes_compliance is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"stream_users_compliance should have at least 'self' parameter" + ), f"likes_compliance should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] + required_params = [] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from stream_users_compliance" + ), f"Required parameter '{required_param}' missing from likes_compliance" # Check optional parameters have defaults (excluding 'self') optional_params = [ "backfill_minutes", @@ -525,32 +603,32 @@ def test_stream_users_compliance_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_stream_users_compliance_return_annotation(self): - """Test that stream_users_compliance has proper return type annotation.""" - method = getattr(StreamClient, "stream_users_compliance") + def test_likes_compliance_return_annotation(self): + """Test that likes_compliance has proper return type annotation.""" + method = getattr(StreamClient, "likes_compliance") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_users_compliance should have return type annotation" + ), f"Method likes_compliance should have return type annotation" - def test_stream_posts_firehose_ko_exists(self): - """Test that stream_posts_firehose_ko method exists with correct signature.""" + def test_users_compliance_exists(self): + """Test that users_compliance method exists with correct signature.""" # Check method exists - method = getattr(StreamClient, "stream_posts_firehose_ko", None) + method = getattr(StreamClient, "users_compliance", None) assert ( method is not None - ), f"Method stream_posts_firehose_ko does not exist on StreamClient" + ), f"Method users_compliance does not exist on StreamClient" # Check method is callable - assert callable(method), f"stream_posts_firehose_ko is not callable" + assert callable(method), f"users_compliance is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"stream_posts_firehose_ko should have at least 'self' parameter" + ), f"users_compliance should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -561,7 +639,7 @@ def test_stream_posts_firehose_ko_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose_ko" + ), f"Required parameter '{required_param}' missing from users_compliance" # Check optional parameters have defaults (excluding 'self') optional_params = [ "backfill_minutes", @@ -576,77 +654,32 @@ def test_stream_posts_firehose_ko_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_stream_posts_firehose_ko_return_annotation(self): - """Test that stream_posts_firehose_ko has proper return type annotation.""" - method = getattr(StreamClient, "stream_posts_firehose_ko") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose_ko should have return type annotation" - - - def test_get_rule_counts_exists(self): - """Test that get_rule_counts method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "get_rule_counts", None) - assert ( - method is not None - ), f"Method get_rule_counts does not exist on StreamClient" - # Check method is callable - assert callable(method), f"get_rule_counts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_rule_counts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_rule_counts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_rule_counts_return_annotation(self): - """Test that get_rule_counts has proper return type annotation.""" - method = getattr(StreamClient, "get_rule_counts") + def test_users_compliance_return_annotation(self): + """Test that users_compliance has proper return type annotation.""" + method = getattr(StreamClient, "users_compliance") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_rule_counts should have return type annotation" + ), f"Method users_compliance should have return type annotation" - def test_stream_posts_firehose_exists(self): - """Test that stream_posts_firehose method exists with correct signature.""" + def test_posts_firehose_en_exists(self): + """Test that posts_firehose_en method exists with correct signature.""" # Check method exists - method = getattr(StreamClient, "stream_posts_firehose", None) + method = getattr(StreamClient, "posts_firehose_en", None) assert ( method is not None - ), f"Method stream_posts_firehose does not exist on StreamClient" + ), f"Method posts_firehose_en does not exist on StreamClient" # Check method is callable - assert callable(method), f"stream_posts_firehose is not callable" + assert callable(method), f"posts_firehose_en is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"stream_posts_firehose should have at least 'self' parameter" + ), f"posts_firehose_en should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -657,7 +690,7 @@ def test_stream_posts_firehose_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose" + ), f"Required parameter '{required_param}' missing from posts_firehose_en" # Check optional parameters have defaults (excluding 'self') optional_params = [ "backfill_minutes", @@ -672,32 +705,32 @@ def test_stream_posts_firehose_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_stream_posts_firehose_return_annotation(self): - """Test that stream_posts_firehose has proper return type annotation.""" - method = getattr(StreamClient, "stream_posts_firehose") + def test_posts_firehose_en_return_annotation(self): + """Test that posts_firehose_en has proper return type annotation.""" + method = getattr(StreamClient, "posts_firehose_en") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose should have return type annotation" + ), f"Method posts_firehose_en should have return type annotation" - def test_stream_posts_sample10_exists(self): - """Test that stream_posts_sample10 method exists with correct signature.""" + def test_posts_firehose_ja_exists(self): + """Test that posts_firehose_ja method exists with correct signature.""" # Check method exists - method = getattr(StreamClient, "stream_posts_sample10", None) + method = getattr(StreamClient, "posts_firehose_ja", None) assert ( method is not None - ), f"Method stream_posts_sample10 does not exist on StreamClient" + ), f"Method posts_firehose_ja does not exist on StreamClient" # Check method is callable - assert callable(method), f"stream_posts_sample10 is not callable" + assert callable(method), f"posts_firehose_ja is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"stream_posts_sample10 should have at least 'self' parameter" + ), f"posts_firehose_ja should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -708,7 +741,7 @@ def test_stream_posts_sample10_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_sample10" + ), f"Required parameter '{required_param}' missing from posts_firehose_ja" # Check optional parameters have defaults (excluding 'self') optional_params = [ "backfill_minutes", @@ -723,32 +756,32 @@ def test_stream_posts_sample10_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_stream_posts_sample10_return_annotation(self): - """Test that stream_posts_sample10 has proper return type annotation.""" - method = getattr(StreamClient, "stream_posts_sample10") + def test_posts_firehose_ja_return_annotation(self): + """Test that posts_firehose_ja has proper return type annotation.""" + method = getattr(StreamClient, "posts_firehose_ja") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_sample10 should have return type annotation" + ), f"Method posts_firehose_ja should have return type annotation" - def test_stream_likes_sample10_exists(self): - """Test that stream_likes_sample10 method exists with correct signature.""" + def test_posts_firehose_ko_exists(self): + """Test that posts_firehose_ko method exists with correct signature.""" # Check method exists - method = getattr(StreamClient, "stream_likes_sample10", None) + method = getattr(StreamClient, "posts_firehose_ko", None) assert ( method is not None - ), f"Method stream_likes_sample10 does not exist on StreamClient" + ), f"Method posts_firehose_ko does not exist on StreamClient" # Check method is callable - assert callable(method), f"stream_likes_sample10 is not callable" + assert callable(method), f"posts_firehose_ko is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"stream_likes_sample10 should have at least 'self' parameter" + ), f"posts_firehose_ko should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -759,7 +792,7 @@ def test_stream_likes_sample10_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from stream_likes_sample10" + ), f"Required parameter '{required_param}' missing from posts_firehose_ko" # Check optional parameters have defaults (excluding 'self') optional_params = [ "backfill_minutes", @@ -774,86 +807,41 @@ def test_stream_likes_sample10_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_stream_likes_sample10_return_annotation(self): - """Test that stream_likes_sample10 has proper return type annotation.""" - method = getattr(StreamClient, "stream_likes_sample10") + def test_posts_firehose_ko_return_annotation(self): + """Test that posts_firehose_ko has proper return type annotation.""" + method = getattr(StreamClient, "posts_firehose_ko") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_likes_sample10 should have return type annotation" + ), f"Method posts_firehose_ko should have return type annotation" - def test_stream_labels_compliance_exists(self): - """Test that stream_labels_compliance method exists with correct signature.""" + def test_posts_sample10_exists(self): + """Test that posts_sample10 method exists with correct signature.""" # Check method exists - method = getattr(StreamClient, "stream_labels_compliance", None) + method = getattr(StreamClient, "posts_sample10", None) assert ( method is not None - ), f"Method stream_labels_compliance does not exist on StreamClient" + ), f"Method posts_sample10 does not exist on StreamClient" # Check method is callable - assert callable(method), f"stream_labels_compliance is not callable" + assert callable(method), f"posts_sample10 is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_labels_compliance should have at least 'self' parameter" + assert len(params) >= 1, f"posts_sample10 should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_labels_compliance" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", + required_params = [ + "partition", ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_labels_compliance_return_annotation(self): - """Test that stream_labels_compliance has proper return type annotation.""" - method = getattr(StreamClient, "stream_labels_compliance") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_labels_compliance should have return type annotation" - - - def test_stream_posts_exists(self): - """Test that stream_posts method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "stream_posts", None) - assert method is not None, f"Method stream_posts does not exist on StreamClient" - # Check method is callable - assert callable(method), f"stream_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"stream_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts" + ), f"Required parameter '{required_param}' missing from posts_sample10" # Check optional parameters have defaults (excluding 'self') optional_params = [ "backfill_minutes", @@ -868,36 +856,36 @@ def test_stream_posts_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_stream_posts_return_annotation(self): - """Test that stream_posts has proper return type annotation.""" - method = getattr(StreamClient, "stream_posts") + def test_posts_sample10_return_annotation(self): + """Test that posts_sample10 has proper return type annotation.""" + method = getattr(StreamClient, "posts_sample10") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts should have return type annotation" + ), f"Method posts_sample10 should have return type annotation" def test_all_expected_methods_exist(self): """Test that all expected methods exist on the client.""" expected_methods = [ - "stream_likes_firehose", - "stream_likes_compliance", - "stream_posts_firehose_pt", - "stream_posts_compliance", - "stream_posts_firehose_ja", - "stream_posts_firehose_en", - "stream_posts_sample", + "likes_sample10", + "posts_sample", + "get_rule_counts", + "posts_firehose_pt", + "labels_compliance", + "likes_firehose", + "posts", + "posts_firehose", + "posts_compliance", "get_rules", "update_rules", - "stream_users_compliance", - "stream_posts_firehose_ko", - "get_rule_counts", - "stream_posts_firehose", - "stream_posts_sample10", - "stream_likes_sample10", - "stream_labels_compliance", - "stream_posts", + "likes_compliance", + "users_compliance", + "posts_firehose_en", + "posts_firehose_ja", + "posts_firehose_ko", + "posts_sample10", ] for expected_method in expected_methods: assert hasattr( diff --git a/xdk/python/tests/trends/test_contracts.py b/xdk/python/tests/trends/test_contracts.py index adc6a2b2..99c75745 100644 --- a/xdk/python/tests/trends/test_contracts.py +++ b/xdk/python/tests/trends/test_contracts.py @@ -1,8 +1,8 @@ """ -Auto-generated contract tests for Trends client. +Auto-generated contract tests for {"class_name": "Trends", "display_name": "trends", "import_name": "trends", "original": ["trends"], "property_name": "trends"} client. This module contains tests that validate the request/response contracts -of the Trends client against the OpenAPI specification. +of the {"class_name": "Trends", "display_name": "trends", "import_name": "trends", "original": ["trends"], "property_name": "trends"} client against the OpenAPI specification. Generated automatically - do not edit manually. """ @@ -24,8 +24,8 @@ def setup_class(self): self.trends_client = getattr(self.client, "trends") - def test_get_users_personalized_trends_request_structure(self): - """Test get_users_personalized_trends request structure.""" + def test_get_by_woeid_request_structure(self): + """Test get_by_woeid request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -38,10 +38,11 @@ def test_get_users_personalized_trends_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters + kwargs["woeid"] = 42 # Add request body if required # Call the method try: - method = getattr(self.trends_client, "get_users_personalized_trends") + method = getattr(self.trends_client, "get_by_woeid") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -51,7 +52,7 @@ def test_get_users_personalized_trends_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/personalized_trends" + expected_path = "/2/trends/by/woeid/{woeid}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -60,29 +61,27 @@ def test_get_users_personalized_trends_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail( - f"Contract test failed for get_users_personalized_trends: {e}" - ) + pytest.fail(f"Contract test failed for get_by_woeid: {e}") - def test_get_users_personalized_trends_required_parameters(self): - """Test that get_users_personalized_trends handles parameters correctly.""" - method = getattr(self.trends_client, "get_users_personalized_trends") - # No required parameters, method should be callable without args + def test_get_by_woeid_required_parameters(self): + """Test that get_by_woeid handles parameters correctly.""" + method = getattr(self.trends_client, "get_by_woeid") + # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: + # Mock a 400 response (typical for missing required parameters) mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None + mock_response.status_code = 400 + mock_response.json.return_value = {"error": "Missing required parameters"} + mock_response.raise_for_status.side_effect = Exception("Bad Request") mock_session.get.return_value = mock_response - try: + # Call without required parameters should either raise locally or via server response + with pytest.raises((TypeError, ValueError, Exception)): method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - def test_get_users_personalized_trends_response_structure(self): - """Test get_users_personalized_trends response structure validation.""" + def test_get_by_woeid_response_structure(self): + """Test get_by_woeid response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -95,9 +94,10 @@ def test_get_users_personalized_trends_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} + kwargs["woeid"] = 1 # Add request body if required # Call method and verify response structure - method = getattr(self.trends_client, "get_users_personalized_trends") + method = getattr(self.trends_client, "get_by_woeid") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -109,8 +109,8 @@ def test_get_users_personalized_trends_response_structure(self): ) - def test_get_trends_by_woeid_request_structure(self): - """Test get_trends_by_woeid request structure.""" + def test_get_personalized_request_structure(self): + """Test get_personalized request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -123,11 +123,10 @@ def test_get_trends_by_woeid_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["woeid"] = 42 # Add request body if required # Call the method try: - method = getattr(self.trends_client, "get_trends_by_woeid") + method = getattr(self.trends_client, "get_personalized") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -137,7 +136,7 @@ def test_get_trends_by_woeid_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/trends/by/woeid/{woeid}" + expected_path = "/2/users/personalized_trends" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -146,27 +145,27 @@ def test_get_trends_by_woeid_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_trends_by_woeid: {e}") + pytest.fail(f"Contract test failed for get_personalized: {e}") - def test_get_trends_by_woeid_required_parameters(self): - """Test that get_trends_by_woeid handles parameters correctly.""" - method = getattr(self.trends_client, "get_trends_by_woeid") - # Test with missing required parameters - mock the request to avoid network calls + def test_get_personalized_required_parameters(self): + """Test that get_personalized handles parameters correctly.""" + method = getattr(self.trends_client, "get_personalized") + # No required parameters, method should be callable without args with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") + mock_response.status_code = 200 + mock_response.json.return_value = {} + mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): + try: method() + except Exception as e: + pytest.fail(f"Method with no required params should be callable: {e}") - def test_get_trends_by_woeid_response_structure(self): - """Test get_trends_by_woeid response structure validation.""" + def test_get_personalized_response_structure(self): + """Test get_personalized response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -179,10 +178,9 @@ def test_get_trends_by_woeid_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["woeid"] = 1 # Add request body if required # Call method and verify response structure - method = getattr(self.trends_client, "get_trends_by_woeid") + method = getattr(self.trends_client, "get_personalized") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed diff --git a/xdk/python/tests/trends/test_generic.py b/xdk/python/tests/trends/test_generic.py index bbbb1a37..6caf07cc 100644 --- a/xdk/python/tests/trends/test_generic.py +++ b/xdk/python/tests/trends/test_generic.py @@ -1,5 +1,5 @@ """ -Auto-generated generic tests for Trends client. +Auto-generated generic tests for {"class_name": "Trends", "display_name": "trends", "import_name": "trends", "original": ["trends"], "property_name": "trends"} client. This module contains general tests that validate the overall client functionality, imports, and error handling that don't need to be diff --git a/xdk/python/tests/trends/test_structure.py b/xdk/python/tests/trends/test_structure.py index 0078ff19..ec1c3332 100644 --- a/xdk/python/tests/trends/test_structure.py +++ b/xdk/python/tests/trends/test_structure.py @@ -1,8 +1,8 @@ """ -Auto-generated structural tests for Trends client. +Auto-generated structural tests for {"class_name": "Trends", "display_name": "trends", "import_name": "trends", "original": ["trends"], "property_name": "trends"} client. This module contains tests that validate the structure and API surface -of the Trends client. These tests ensure that all expected methods +of the {"class_name": "Trends", "display_name": "trends", "import_name": "trends", "original": ["trends"], "property_name": "trends"} client. These tests ensure that all expected methods exist and have the correct signatures. Generated automatically - do not edit manually. @@ -25,33 +25,33 @@ def setup_class(self): self.trends_client = getattr(self.client, "trends") - def test_get_users_personalized_trends_exists(self): - """Test that get_users_personalized_trends method exists with correct signature.""" + def test_get_by_woeid_exists(self): + """Test that get_by_woeid method exists with correct signature.""" # Check method exists - method = getattr(TrendsClient, "get_users_personalized_trends", None) - assert ( - method is not None - ), f"Method get_users_personalized_trends does not exist on TrendsClient" + method = getattr(TrendsClient, "get_by_woeid", None) + assert method is not None, f"Method get_by_woeid does not exist on TrendsClient" # Check method is callable - assert callable(method), f"get_users_personalized_trends is not callable" + assert callable(method), f"get_by_woeid is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_personalized_trends should have at least 'self' parameter" + assert len(params) >= 1, f"get_by_woeid should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [] + required_params = [ + "woeid", + ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_personalized_trends" + ), f"Required parameter '{required_param}' missing from get_by_woeid" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "max_trends", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -60,47 +60,43 @@ def test_get_users_personalized_trends_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_personalized_trends_return_annotation(self): - """Test that get_users_personalized_trends has proper return type annotation.""" - method = getattr(TrendsClient, "get_users_personalized_trends") + def test_get_by_woeid_return_annotation(self): + """Test that get_by_woeid has proper return type annotation.""" + method = getattr(TrendsClient, "get_by_woeid") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_personalized_trends should have return type annotation" + ), f"Method get_by_woeid should have return type annotation" - def test_get_trends_by_woeid_exists(self): - """Test that get_trends_by_woeid method exists with correct signature.""" + def test_get_personalized_exists(self): + """Test that get_personalized method exists with correct signature.""" # Check method exists - method = getattr(TrendsClient, "get_trends_by_woeid", None) + method = getattr(TrendsClient, "get_personalized", None) assert ( method is not None - ), f"Method get_trends_by_woeid does not exist on TrendsClient" + ), f"Method get_personalized does not exist on TrendsClient" # Check method is callable - assert callable(method), f"get_trends_by_woeid is not callable" + assert callable(method), f"get_personalized is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"get_trends_by_woeid should have at least 'self' parameter" + ), f"get_personalized should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [ - "woeid", - ] + required_params = [] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_trends_by_woeid" + ), f"Required parameter '{required_param}' missing from get_personalized" # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_trends", - ] + optional_params = [] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -109,21 +105,21 @@ def test_get_trends_by_woeid_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_trends_by_woeid_return_annotation(self): - """Test that get_trends_by_woeid has proper return type annotation.""" - method = getattr(TrendsClient, "get_trends_by_woeid") + def test_get_personalized_return_annotation(self): + """Test that get_personalized has proper return type annotation.""" + method = getattr(TrendsClient, "get_personalized") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_trends_by_woeid should have return type annotation" + ), f"Method get_personalized should have return type annotation" def test_all_expected_methods_exist(self): """Test that all expected methods exist on the client.""" expected_methods = [ - "get_users_personalized_trends", - "get_trends_by_woeid", + "get_by_woeid", + "get_personalized", ] for expected_method in expected_methods: assert hasattr( diff --git a/xdk/python/tests/tweets/__init__.py b/xdk/python/tests/tweets/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/tests/tweets/test_contracts.py b/xdk/python/tests/tweets/test_contracts.py deleted file mode 100644 index 337182c0..00000000 --- a/xdk/python/tests/tweets/test_contracts.py +++ /dev/null @@ -1,3134 +0,0 @@ -""" -Auto-generated contract tests for Tweets client. - -This module contains tests that validate the request/response contracts -of the Tweets client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.tweets.client import TweetsClient -from xdk import Client - - -class TestTweetsContracts: - """Test the API contracts of TweetsClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.tweets_client = getattr(self.client, "tweets") - - - def test_unlike_post_request_structure(self): - """Test unlike_post request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - kwargs["tweet_id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "unlike_post") - result = method(**kwargs) - # Verify the request was made - mock_session.delete.assert_called_once() - # Verify request structure - call_args = mock_session.delete.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/likes/{tweet_id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for unlike_post: {e}") - - - def test_unlike_post_required_parameters(self): - """Test that unlike_post handles parameters correctly.""" - method = getattr(self.tweets_client, "unlike_post") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_unlike_post_response_structure(self): - """Test unlike_post response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - kwargs["tweet_id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "unlike_post") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_search_posts_recent_request_structure(self): - """Test search_posts_recent request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["query"] = "test_query" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "search_posts_recent") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/search/recent" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for search_posts_recent: {e}") - - - def test_search_posts_recent_required_parameters(self): - """Test that search_posts_recent handles parameters correctly.""" - method = getattr(self.tweets_client, "search_posts_recent") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_search_posts_recent_response_structure(self): - """Test search_posts_recent response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["query"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "search_posts_recent") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_posts_by_id_request_structure(self): - """Test get_posts_by_id request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_posts_by_id") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/{id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_posts_by_id: {e}") - - - def test_get_posts_by_id_required_parameters(self): - """Test that get_posts_by_id handles parameters correctly.""" - method = getattr(self.tweets_client, "get_posts_by_id") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_posts_by_id_response_structure(self): - """Test get_posts_by_id response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_posts_by_id") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_delete_posts_request_structure(self): - """Test delete_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "delete_posts") - result = method(**kwargs) - # Verify the request was made - mock_session.delete.assert_called_once() - # Verify request structure - call_args = mock_session.delete.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/{id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for delete_posts: {e}") - - - def test_delete_posts_required_parameters(self): - """Test that delete_posts handles parameters correctly.""" - method = getattr(self.tweets_client, "delete_posts") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_delete_posts_response_structure(self): - """Test delete_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "delete_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_lists_posts_request_structure(self): - """Test get_lists_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_lists_posts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/lists/{id}/tweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_lists_posts: {e}") - - - def test_get_lists_posts_required_parameters(self): - """Test that get_lists_posts handles parameters correctly.""" - method = getattr(self.tweets_client, "get_lists_posts") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_lists_posts_response_structure(self): - """Test get_lists_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_lists_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_users_posts_request_structure(self): - """Test get_users_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_users_posts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/tweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_users_posts: {e}") - - - def test_get_users_posts_required_parameters(self): - """Test that get_users_posts handles parameters correctly.""" - method = getattr(self.tweets_client, "get_users_posts") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_users_posts_response_structure(self): - """Test get_users_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_users_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_firehose_pt_request_structure(self): - """Test stream_posts_firehose_pt request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "stream_posts_firehose_pt") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/firehose/stream/lang/pt" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose_pt: {e}") - - - def test_stream_posts_firehose_pt_required_parameters(self): - """Test that stream_posts_firehose_pt handles parameters correctly.""" - method = getattr(self.tweets_client, "stream_posts_firehose_pt") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_firehose_pt_response_structure(self): - """Test stream_posts_firehose_pt response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "stream_posts_firehose_pt") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_spaces_posts_request_structure(self): - """Test get_spaces_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_id" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_spaces_posts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/spaces/{id}/tweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_spaces_posts: {e}") - - - def test_get_spaces_posts_required_parameters(self): - """Test that get_spaces_posts handles parameters correctly.""" - method = getattr(self.tweets_client, "get_spaces_posts") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_spaces_posts_response_structure(self): - """Test get_spaces_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_spaces_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_firehose_ja_request_structure(self): - """Test stream_posts_firehose_ja request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "stream_posts_firehose_ja") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/firehose/stream/lang/ja" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose_ja: {e}") - - - def test_stream_posts_firehose_ja_required_parameters(self): - """Test that stream_posts_firehose_ja handles parameters correctly.""" - method = getattr(self.tweets_client, "stream_posts_firehose_ja") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_firehose_ja_response_structure(self): - """Test stream_posts_firehose_ja response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "stream_posts_firehose_ja") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_hide_posts_reply_request_structure(self): - """Test hide_posts_reply request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.put.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["tweet_id"] = "test_value" - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import HidePostsReplyRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = HidePostsReplyRequest() - # Call the method - try: - method = getattr(self.tweets_client, "hide_posts_reply") - result = method(**kwargs) - # Verify the request was made - mock_session.put.assert_called_once() - # Verify request structure - call_args = mock_session.put.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/{tweet_id}/hidden" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for hide_posts_reply: {e}") - - - def test_hide_posts_reply_required_parameters(self): - """Test that hide_posts_reply handles parameters correctly.""" - method = getattr(self.tweets_client, "hide_posts_reply") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.put.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_hide_posts_reply_response_structure(self): - """Test hide_posts_reply response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.put.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["tweet_id"] = "test" - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import HidePostsReplyRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = HidePostsReplyRequest() - # Call method and verify response structure - method = getattr(self.tweets_client, "hide_posts_reply") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_users_liked_posts_request_structure(self): - """Test get_users_liked_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_users_liked_posts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/liked_tweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_users_liked_posts: {e}") - - - def test_get_users_liked_posts_required_parameters(self): - """Test that get_users_liked_posts handles parameters correctly.""" - method = getattr(self.tweets_client, "get_users_liked_posts") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_users_liked_posts_response_structure(self): - """Test get_users_liked_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_users_liked_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_firehose_en_request_structure(self): - """Test stream_posts_firehose_en request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "stream_posts_firehose_en") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/firehose/stream/lang/en" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose_en: {e}") - - - def test_stream_posts_firehose_en_required_parameters(self): - """Test that stream_posts_firehose_en handles parameters correctly.""" - method = getattr(self.tweets_client, "stream_posts_firehose_en") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_firehose_en_response_structure(self): - """Test stream_posts_firehose_en response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "stream_posts_firehose_en") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_sample_request_structure(self): - """Test stream_posts_sample request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "stream_posts_sample") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/sample/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_sample: {e}") - - - def test_stream_posts_sample_required_parameters(self): - """Test that stream_posts_sample handles parameters correctly.""" - method = getattr(self.tweets_client, "stream_posts_sample") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_stream_posts_sample_response_structure(self): - """Test stream_posts_sample response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "stream_posts_sample") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_rules_request_structure(self): - """Test get_rules request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_rules") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/search/stream/rules" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_rules: {e}") - - - def test_get_rules_required_parameters(self): - """Test that get_rules handles parameters correctly.""" - method = getattr(self.tweets_client, "get_rules") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_get_rules_response_structure(self): - """Test get_rules response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_rules") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_update_rules_request_structure(self): - """Test update_rules request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import UpdateRulesRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = UpdateRulesRequest() - # Call the method - try: - method = getattr(self.tweets_client, "update_rules") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/search/stream/rules" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for update_rules: {e}") - - - def test_update_rules_required_parameters(self): - """Test that update_rules handles parameters correctly.""" - method = getattr(self.tweets_client, "update_rules") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_update_rules_response_structure(self): - """Test update_rules response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import UpdateRulesRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = UpdateRulesRequest() - # Call method and verify response structure - method = getattr(self.tweets_client, "update_rules") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_spaces_buyers_request_structure(self): - """Test get_spaces_buyers request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_id" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_spaces_buyers") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/spaces/{id}/buyers" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_spaces_buyers: {e}") - - - def test_get_spaces_buyers_required_parameters(self): - """Test that get_spaces_buyers handles parameters correctly.""" - method = getattr(self.tweets_client, "get_spaces_buyers") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_spaces_buyers_response_structure(self): - """Test get_spaces_buyers response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_spaces_buyers") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_posts_by_ids_request_structure(self): - """Test get_posts_by_ids request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["ids"] = ["test_item"] - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_posts_by_ids") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_posts_by_ids: {e}") - - - def test_get_posts_by_ids_required_parameters(self): - """Test that get_posts_by_ids handles parameters correctly.""" - method = getattr(self.tweets_client, "get_posts_by_ids") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_posts_by_ids_response_structure(self): - """Test get_posts_by_ids response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["ids"] = ["test"] - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_posts_by_ids") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_create_posts_request_structure(self): - """Test create_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 201 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import CreatePostsRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatePostsRequest() - # Call the method - try: - method = getattr(self.tweets_client, "create_posts") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for create_posts: {e}") - - - def test_create_posts_required_parameters(self): - """Test that create_posts handles parameters correctly.""" - method = getattr(self.tweets_client, "create_posts") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_create_posts_response_structure(self): - """Test create_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 201 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import CreatePostsRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatePostsRequest() - # Call method and verify response structure - method = getattr(self.tweets_client, "create_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_users_timeline_request_structure(self): - """Test get_users_timeline request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_users_timeline") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/timelines/reverse_chronological" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_users_timeline: {e}") - - - def test_get_users_timeline_required_parameters(self): - """Test that get_users_timeline handles parameters correctly.""" - method = getattr(self.tweets_client, "get_users_timeline") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_users_timeline_response_structure(self): - """Test get_users_timeline response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_users_timeline") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_users_mentions_request_structure(self): - """Test get_users_mentions request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_users_mentions") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/mentions" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_users_mentions: {e}") - - - def test_get_users_mentions_required_parameters(self): - """Test that get_users_mentions handles parameters correctly.""" - method = getattr(self.tweets_client, "get_users_mentions") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_users_mentions_response_structure(self): - """Test get_users_mentions response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_users_mentions") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_insights_historical_request_structure(self): - """Test get_insights_historical request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["tweet_ids"] = ["test_item"] - kwargs["end_time"] = "test_end_time" - kwargs["start_time"] = "test_start_time" - kwargs["granularity"] = "test_granularity" - kwargs["requested_metrics"] = ["test_item"] - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_insights_historical") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/insights/historical" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_insights_historical: {e}") - - - def test_get_insights_historical_required_parameters(self): - """Test that get_insights_historical handles parameters correctly.""" - method = getattr(self.tweets_client, "get_insights_historical") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_insights_historical_response_structure(self): - """Test get_insights_historical response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["tweet_ids"] = ["test"] - kwargs["end_time"] = "test_value" - kwargs["start_time"] = "test_value" - kwargs["granularity"] = "test_value" - kwargs["requested_metrics"] = ["test"] - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_insights_historical") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_posts_counts_recent_request_structure(self): - """Test get_posts_counts_recent request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["query"] = "test_query" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_posts_counts_recent") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/counts/recent" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_posts_counts_recent: {e}") - - - def test_get_posts_counts_recent_required_parameters(self): - """Test that get_posts_counts_recent handles parameters correctly.""" - method = getattr(self.tweets_client, "get_posts_counts_recent") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_posts_counts_recent_response_structure(self): - """Test get_posts_counts_recent response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["query"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_posts_counts_recent") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_firehose_ko_request_structure(self): - """Test stream_posts_firehose_ko request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "stream_posts_firehose_ko") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/firehose/stream/lang/ko" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose_ko: {e}") - - - def test_stream_posts_firehose_ko_required_parameters(self): - """Test that stream_posts_firehose_ko handles parameters correctly.""" - method = getattr(self.tweets_client, "stream_posts_firehose_ko") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_firehose_ko_response_structure(self): - """Test stream_posts_firehose_ko response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "stream_posts_firehose_ko") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_posts_analytics_request_structure(self): - """Test get_posts_analytics request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["ids"] = ["test_item"] - kwargs["end_time"] = "test_end_time" - kwargs["start_time"] = "test_start_time" - kwargs["granularity"] = "test_granularity" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_posts_analytics") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/analytics" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_posts_analytics: {e}") - - - def test_get_posts_analytics_required_parameters(self): - """Test that get_posts_analytics handles parameters correctly.""" - method = getattr(self.tweets_client, "get_posts_analytics") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_posts_analytics_response_structure(self): - """Test get_posts_analytics response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["ids"] = ["test"] - kwargs["end_time"] = "test_value" - kwargs["start_time"] = "test_value" - kwargs["granularity"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_posts_analytics") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_rule_counts_request_structure(self): - """Test get_rule_counts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_rule_counts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/search/stream/rules/counts" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_rule_counts: {e}") - - - def test_get_rule_counts_required_parameters(self): - """Test that get_rule_counts handles parameters correctly.""" - method = getattr(self.tweets_client, "get_rule_counts") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_get_rule_counts_response_structure(self): - """Test get_rule_counts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_rule_counts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_posts_quoted_posts_request_structure(self): - """Test get_posts_quoted_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_posts_quoted_posts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/{id}/quote_tweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_posts_quoted_posts: {e}") - - - def test_get_posts_quoted_posts_required_parameters(self): - """Test that get_posts_quoted_posts handles parameters correctly.""" - method = getattr(self.tweets_client, "get_posts_quoted_posts") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_posts_quoted_posts_response_structure(self): - """Test get_posts_quoted_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_posts_quoted_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_firehose_request_structure(self): - """Test stream_posts_firehose request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "stream_posts_firehose") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/firehose/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose: {e}") - - - def test_stream_posts_firehose_required_parameters(self): - """Test that stream_posts_firehose handles parameters correctly.""" - method = getattr(self.tweets_client, "stream_posts_firehose") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_firehose_response_structure(self): - """Test stream_posts_firehose response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "stream_posts_firehose") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_insights28_hr_request_structure(self): - """Test get_insights28_hr request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["tweet_ids"] = ["test_item"] - kwargs["granularity"] = "test_granularity" - kwargs["requested_metrics"] = ["test_item"] - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_insights28_hr") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/insights/28hr" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_insights28_hr: {e}") - - - def test_get_insights28_hr_required_parameters(self): - """Test that get_insights28_hr handles parameters correctly.""" - method = getattr(self.tweets_client, "get_insights28_hr") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_insights28_hr_response_structure(self): - """Test get_insights28_hr response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["tweet_ids"] = ["test"] - kwargs["granularity"] = "test_value" - kwargs["requested_metrics"] = ["test"] - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_insights28_hr") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_posts_reposts_request_structure(self): - """Test get_posts_reposts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_posts_reposts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/{id}/retweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_posts_reposts: {e}") - - - def test_get_posts_reposts_required_parameters(self): - """Test that get_posts_reposts handles parameters correctly.""" - method = getattr(self.tweets_client, "get_posts_reposts") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_posts_reposts_response_structure(self): - """Test get_posts_reposts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_posts_reposts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_sample10_request_structure(self): - """Test stream_posts_sample10 request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "stream_posts_sample10") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/sample10/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_sample10: {e}") - - - def test_stream_posts_sample10_required_parameters(self): - """Test that stream_posts_sample10 handles parameters correctly.""" - method = getattr(self.tweets_client, "stream_posts_sample10") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_sample10_response_structure(self): - """Test stream_posts_sample10 response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "stream_posts_sample10") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_repost_post_request_structure(self): - """Test repost_post request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import RepostPostRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = RepostPostRequest() - # Call the method - try: - method = getattr(self.tweets_client, "repost_post") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/retweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for repost_post: {e}") - - - def test_repost_post_required_parameters(self): - """Test that repost_post handles parameters correctly.""" - method = getattr(self.tweets_client, "repost_post") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_repost_post_response_structure(self): - """Test repost_post response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import RepostPostRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = RepostPostRequest() - # Call method and verify response structure - method = getattr(self.tweets_client, "repost_post") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_search_posts_all_request_structure(self): - """Test search_posts_all request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["query"] = "test_query" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "search_posts_all") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/search/all" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for search_posts_all: {e}") - - - def test_search_posts_all_required_parameters(self): - """Test that search_posts_all handles parameters correctly.""" - method = getattr(self.tweets_client, "search_posts_all") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_search_posts_all_response_structure(self): - """Test search_posts_all response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["query"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "search_posts_all") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_unrepost_post_request_structure(self): - """Test unrepost_post request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - kwargs["source_tweet_id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "unrepost_post") - result = method(**kwargs) - # Verify the request was made - mock_session.delete.assert_called_once() - # Verify request structure - call_args = mock_session.delete.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/retweets/{source_tweet_id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for unrepost_post: {e}") - - - def test_unrepost_post_required_parameters(self): - """Test that unrepost_post handles parameters correctly.""" - method = getattr(self.tweets_client, "unrepost_post") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_unrepost_post_response_structure(self): - """Test unrepost_post response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - kwargs["source_tweet_id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "unrepost_post") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_request_structure(self): - """Test stream_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "stream_posts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/search/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts: {e}") - - - def test_stream_posts_required_parameters(self): - """Test that stream_posts handles parameters correctly.""" - method = getattr(self.tweets_client, "stream_posts") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_stream_posts_response_structure(self): - """Test stream_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "stream_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_like_post_request_structure(self): - """Test like_post request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import LikePostRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = LikePostRequest() - # Call the method - try: - method = getattr(self.tweets_client, "like_post") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/likes" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for like_post: {e}") - - - def test_like_post_required_parameters(self): - """Test that like_post handles parameters correctly.""" - method = getattr(self.tweets_client, "like_post") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_like_post_response_structure(self): - """Test like_post response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import LikePostRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = LikePostRequest() - # Call method and verify response structure - method = getattr(self.tweets_client, "like_post") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_posts_counts_all_request_structure(self): - """Test get_posts_counts_all request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["query"] = "test_query" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_posts_counts_all") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/counts/all" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_posts_counts_all: {e}") - - - def test_get_posts_counts_all_required_parameters(self): - """Test that get_posts_counts_all handles parameters correctly.""" - method = getattr(self.tweets_client, "get_posts_counts_all") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_posts_counts_all_response_structure(self): - """Test get_posts_counts_all response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["query"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_posts_counts_all") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/tests/tweets/test_generic.py b/xdk/python/tests/tweets/test_generic.py deleted file mode 100644 index 281263ab..00000000 --- a/xdk/python/tests/tweets/test_generic.py +++ /dev/null @@ -1,122 +0,0 @@ -""" -Auto-generated generic tests for Tweets client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.tweets.client import TweetsClient -from xdk import Client - - -class TestTweetsGeneric: - """Generic tests for TweetsClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.tweets_client = getattr(self.client, "tweets") - - - def test_client_exists(self): - """Test that TweetsClient class exists and is importable.""" - assert TweetsClient is not None - assert hasattr(TweetsClient, "__name__") - assert TweetsClient.__name__ == "TweetsClient" - - - def test_client_initialization(self): - """Test that TweetsClient can be initialized properly.""" - assert self.tweets_client is not None - assert isinstance(self.tweets_client, TweetsClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(TweetsClient) - if not name.startswith("_") and callable(getattr(TweetsClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.tweets_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "tweets") - # Client should have standard Python object features - assert hasattr(self.tweets_client, "__class__") - assert hasattr(self.tweets_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.tweets_client) - if not name.startswith("_") and callable(getattr(self.tweets_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"TweetsClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(TweetsClient) - if not name.startswith("_") and callable(getattr(TweetsClient, name)) - ] - for method_name in public_methods: - method = getattr(TweetsClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/tests/tweets/test_pagination.py b/xdk/python/tests/tweets/test_pagination.py deleted file mode 100644 index ecf332e6..00000000 --- a/xdk/python/tests/tweets/test_pagination.py +++ /dev/null @@ -1,1630 +0,0 @@ -""" -Auto-generated pagination tests for Tweets client. - -This module contains tests that validate pagination functionality -using the Cursor class for methods that support pagination. - -Generated automatically - do not edit manually. -""" - -import pytest -from unittest.mock import Mock, patch -from xdk.tweets.client import TweetsClient -from xdk import Client, Cursor, cursor, PaginationError - - -class TestTweetsPagination: - """Test pagination functionality for TweetsClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.tweets_client = getattr(self.client, "tweets") - - - def test_search_posts_recent_cursor_creation(self): - """Test that search_posts_recent can be used with Cursor.""" - method = getattr(self.tweets_client, "search_posts_recent") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_query", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method searchPostsRecent should support pagination") - - - def test_search_posts_recent_cursor_pages(self): - """Test pagination with pages() for search_posts_recent.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "search_posts_recent") - test_cursor = cursor(method, "test_query", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_search_posts_recent_cursor_items(self): - """Test pagination with items() for search_posts_recent.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "search_posts_recent") - test_cursor = cursor(method, "test_query", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_search_posts_recent_pagination_parameters(self): - """Test that pagination parameters are handled correctly for search_posts_recent.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "search_posts_recent") - # Test with max_results parameter - test_cursor = cursor(method, "test_query", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [], - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_query", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_lists_posts_cursor_creation(self): - """Test that get_lists_posts can be used with Cursor.""" - method = getattr(self.tweets_client, "get_lists_posts") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getListsPosts should support pagination") - - - def test_get_lists_posts_cursor_pages(self): - """Test pagination with pages() for get_lists_posts.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "get_lists_posts") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_lists_posts_cursor_items(self): - """Test pagination with items() for get_lists_posts.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "get_lists_posts") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_lists_posts_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_lists_posts.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "get_lists_posts") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [], - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_users_posts_cursor_creation(self): - """Test that get_users_posts can be used with Cursor.""" - method = getattr(self.tweets_client, "get_users_posts") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersPosts should support pagination") - - - def test_get_users_posts_cursor_pages(self): - """Test pagination with pages() for get_users_posts.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "get_users_posts") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_posts_cursor_items(self): - """Test pagination with items() for get_users_posts.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "get_users_posts") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_posts_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_posts.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "get_users_posts") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [], - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_users_liked_posts_cursor_creation(self): - """Test that get_users_liked_posts can be used with Cursor.""" - method = getattr(self.tweets_client, "get_users_liked_posts") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersLikedPosts should support pagination") - - - def test_get_users_liked_posts_cursor_pages(self): - """Test pagination with pages() for get_users_liked_posts.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "get_users_liked_posts") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_liked_posts_cursor_items(self): - """Test pagination with items() for get_users_liked_posts.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "get_users_liked_posts") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_liked_posts_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_liked_posts.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "get_users_liked_posts") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [], - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_rules_cursor_creation(self): - """Test that get_rules can be used with Cursor.""" - method = getattr(self.tweets_client, "get_rules") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getRules should support pagination") - - - def test_get_rules_cursor_pages(self): - """Test pagination with pages() for get_rules.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "get_rules") - test_cursor = cursor(method, max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_rules_cursor_items(self): - """Test pagination with items() for get_rules.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "get_rules") - test_cursor = cursor(method, max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_rules_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_rules.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "get_rules") - # Test with max_results parameter - test_cursor = cursor(method, max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [], - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_spaces_buyers_cursor_creation(self): - """Test that get_spaces_buyers can be used with Cursor.""" - method = getattr(self.tweets_client, "get_spaces_buyers") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getSpacesBuyers should support pagination") - - - def test_get_spaces_buyers_cursor_pages(self): - """Test pagination with pages() for get_spaces_buyers.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "get_spaces_buyers") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_spaces_buyers_cursor_items(self): - """Test pagination with items() for get_spaces_buyers.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "get_spaces_buyers") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_spaces_buyers_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_spaces_buyers.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "get_spaces_buyers") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [], - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_users_timeline_cursor_creation(self): - """Test that get_users_timeline can be used with Cursor.""" - method = getattr(self.tweets_client, "get_users_timeline") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersTimeline should support pagination") - - - def test_get_users_timeline_cursor_pages(self): - """Test pagination with pages() for get_users_timeline.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "get_users_timeline") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_timeline_cursor_items(self): - """Test pagination with items() for get_users_timeline.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "get_users_timeline") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_timeline_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_timeline.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "get_users_timeline") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [], - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_users_mentions_cursor_creation(self): - """Test that get_users_mentions can be used with Cursor.""" - method = getattr(self.tweets_client, "get_users_mentions") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersMentions should support pagination") - - - def test_get_users_mentions_cursor_pages(self): - """Test pagination with pages() for get_users_mentions.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "get_users_mentions") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_mentions_cursor_items(self): - """Test pagination with items() for get_users_mentions.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "get_users_mentions") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_mentions_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_mentions.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "get_users_mentions") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [], - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_posts_quoted_posts_cursor_creation(self): - """Test that get_posts_quoted_posts can be used with Cursor.""" - method = getattr(self.tweets_client, "get_posts_quoted_posts") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getPostsQuotedPosts should support pagination") - - - def test_get_posts_quoted_posts_cursor_pages(self): - """Test pagination with pages() for get_posts_quoted_posts.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "get_posts_quoted_posts") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_posts_quoted_posts_cursor_items(self): - """Test pagination with items() for get_posts_quoted_posts.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "get_posts_quoted_posts") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_posts_quoted_posts_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_posts_quoted_posts.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "get_posts_quoted_posts") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [], - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_posts_reposts_cursor_creation(self): - """Test that get_posts_reposts can be used with Cursor.""" - method = getattr(self.tweets_client, "get_posts_reposts") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getPostsReposts should support pagination") - - - def test_get_posts_reposts_cursor_pages(self): - """Test pagination with pages() for get_posts_reposts.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "get_posts_reposts") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_posts_reposts_cursor_items(self): - """Test pagination with items() for get_posts_reposts.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "get_posts_reposts") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_posts_reposts_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_posts_reposts.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "get_posts_reposts") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [], - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_search_posts_all_cursor_creation(self): - """Test that search_posts_all can be used with Cursor.""" - method = getattr(self.tweets_client, "search_posts_all") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_query", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method searchPostsAll should support pagination") - - - def test_search_posts_all_cursor_pages(self): - """Test pagination with pages() for search_posts_all.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "search_posts_all") - test_cursor = cursor(method, "test_query", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_search_posts_all_cursor_items(self): - """Test pagination with items() for search_posts_all.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "search_posts_all") - test_cursor = cursor(method, "test_query", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_search_posts_all_pagination_parameters(self): - """Test that pagination parameters are handled correctly for search_posts_all.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "search_posts_all") - # Test with max_results parameter - test_cursor = cursor(method, "test_query", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [], - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_query", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_pagination_edge_cases(self): - """Test pagination edge cases.""" - with patch.object(self.client, "session") as mock_session: - # Test empty response - empty_response = Mock() - empty_response.status_code = 200 - empty_response.json.return_value = {"data": [], "meta": {"result_count": 0}} - empty_response.raise_for_status.return_value = None - mock_session.get.return_value = empty_response - # Pick first paginatable method for testing - method = getattr(self.tweets_client, "search_posts_recent") - test_cursor = cursor(method, "test_query", max_results=10) - # Should handle empty responses gracefully - pages = list(test_cursor.pages(1)) - assert len(pages) == 1, "Should get one page even if empty" - items = list(test_cursor.items(10)) - assert len(items) == 0, "Should get no items from empty response" - - - def test_non_paginatable_method_raises_error(self): - """Test that non-paginatable methods raise PaginationError.""" - # Create a mock method that doesn't support pagination - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def test_cursor_class_functionality(self): - """Test basic Cursor class functionality.""" - # Test that Cursor can be imported and instantiated - from xdk.paginator import Cursor - assert Cursor is not None - # Test cursor factory function - from xdk.paginator import cursor as cursor_factory - assert cursor_factory is not None diff --git a/xdk/python/tests/tweets/test_structure.py b/xdk/python/tests/tweets/test_structure.py deleted file mode 100644 index 09408b42..00000000 --- a/xdk/python/tests/tweets/test_structure.py +++ /dev/null @@ -1,2052 +0,0 @@ -""" -Auto-generated structural tests for Tweets client. - -This module contains tests that validate the structure and API surface -of the Tweets client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.tweets.client import TweetsClient -from xdk import Client - - -class TestTweetsStructure: - """Test the structure of TweetsClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.tweets_client = getattr(self.client, "tweets") - - - def test_unlike_post_exists(self): - """Test that unlike_post method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "unlike_post", None) - assert method is not None, f"Method unlike_post does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"unlike_post is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"unlike_post should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - "tweet_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from unlike_post" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_unlike_post_return_annotation(self): - """Test that unlike_post has proper return type annotation.""" - method = getattr(TweetsClient, "unlike_post") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method unlike_post should have return type annotation" - - - def test_search_posts_recent_exists(self): - """Test that search_posts_recent method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "search_posts_recent", None) - assert ( - method is not None - ), f"Method search_posts_recent does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"search_posts_recent is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"search_posts_recent should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "query", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from search_posts_recent" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "start_time", - "end_time", - "since_id", - "until_id", - "max_results", - "next_token", - "pagination_token", - "sort_order", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_search_posts_recent_return_annotation(self): - """Test that search_posts_recent has proper return type annotation.""" - method = getattr(TweetsClient, "search_posts_recent") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method search_posts_recent should have return type annotation" - - - def test_search_posts_recent_pagination_params(self): - """Test that search_posts_recent has pagination parameters.""" - method = getattr(TweetsClient, "search_posts_recent") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method search_posts_recent should have pagination parameters" - - - def test_get_posts_by_id_exists(self): - """Test that get_posts_by_id method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_posts_by_id", None) - assert ( - method is not None - ), f"Method get_posts_by_id does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_posts_by_id is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_posts_by_id should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_posts_by_id" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_posts_by_id_return_annotation(self): - """Test that get_posts_by_id has proper return type annotation.""" - method = getattr(TweetsClient, "get_posts_by_id") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_posts_by_id should have return type annotation" - - - def test_delete_posts_exists(self): - """Test that delete_posts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "delete_posts", None) - assert method is not None, f"Method delete_posts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"delete_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"delete_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from delete_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_delete_posts_return_annotation(self): - """Test that delete_posts has proper return type annotation.""" - method = getattr(TweetsClient, "delete_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method delete_posts should have return type annotation" - - - def test_get_lists_posts_exists(self): - """Test that get_lists_posts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_lists_posts", None) - assert ( - method is not None - ), f"Method get_lists_posts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_lists_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_lists_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_lists_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_lists_posts_return_annotation(self): - """Test that get_lists_posts has proper return type annotation.""" - method = getattr(TweetsClient, "get_lists_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_lists_posts should have return type annotation" - - - def test_get_lists_posts_pagination_params(self): - """Test that get_lists_posts has pagination parameters.""" - method = getattr(TweetsClient, "get_lists_posts") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_lists_posts should have pagination parameters" - - - def test_get_users_posts_exists(self): - """Test that get_users_posts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_users_posts", None) - assert ( - method is not None - ), f"Method get_users_posts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_users_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_users_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "since_id", - "until_id", - "max_results", - "pagination_token", - "exclude", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_users_posts_return_annotation(self): - """Test that get_users_posts has proper return type annotation.""" - method = getattr(TweetsClient, "get_users_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_posts should have return type annotation" - - - def test_get_users_posts_pagination_params(self): - """Test that get_users_posts has pagination parameters.""" - method = getattr(TweetsClient, "get_users_posts") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_posts should have pagination parameters" - - - def test_stream_posts_firehose_pt_exists(self): - """Test that stream_posts_firehose_pt method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "stream_posts_firehose_pt", None) - assert ( - method is not None - ), f"Method stream_posts_firehose_pt does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"stream_posts_firehose_pt is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_firehose_pt should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose_pt" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_firehose_pt_return_annotation(self): - """Test that stream_posts_firehose_pt has proper return type annotation.""" - method = getattr(TweetsClient, "stream_posts_firehose_pt") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose_pt should have return type annotation" - - - def test_get_spaces_posts_exists(self): - """Test that get_spaces_posts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_spaces_posts", None) - assert ( - method is not None - ), f"Method get_spaces_posts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_spaces_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_spaces_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_spaces_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_spaces_posts_return_annotation(self): - """Test that get_spaces_posts has proper return type annotation.""" - method = getattr(TweetsClient, "get_spaces_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_spaces_posts should have return type annotation" - - - def test_stream_posts_firehose_ja_exists(self): - """Test that stream_posts_firehose_ja method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "stream_posts_firehose_ja", None) - assert ( - method is not None - ), f"Method stream_posts_firehose_ja does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"stream_posts_firehose_ja is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_firehose_ja should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose_ja" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_firehose_ja_return_annotation(self): - """Test that stream_posts_firehose_ja has proper return type annotation.""" - method = getattr(TweetsClient, "stream_posts_firehose_ja") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose_ja should have return type annotation" - - - def test_hide_posts_reply_exists(self): - """Test that hide_posts_reply method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "hide_posts_reply", None) - assert ( - method is not None - ), f"Method hide_posts_reply does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"hide_posts_reply is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"hide_posts_reply should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "tweet_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from hide_posts_reply" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_hide_posts_reply_return_annotation(self): - """Test that hide_posts_reply has proper return type annotation.""" - method = getattr(TweetsClient, "hide_posts_reply") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method hide_posts_reply should have return type annotation" - - - def test_get_users_liked_posts_exists(self): - """Test that get_users_liked_posts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_users_liked_posts", None) - assert ( - method is not None - ), f"Method get_users_liked_posts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_users_liked_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_liked_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_users_liked_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_users_liked_posts_return_annotation(self): - """Test that get_users_liked_posts has proper return type annotation.""" - method = getattr(TweetsClient, "get_users_liked_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_liked_posts should have return type annotation" - - - def test_get_users_liked_posts_pagination_params(self): - """Test that get_users_liked_posts has pagination parameters.""" - method = getattr(TweetsClient, "get_users_liked_posts") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_liked_posts should have pagination parameters" - - - def test_stream_posts_firehose_en_exists(self): - """Test that stream_posts_firehose_en method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "stream_posts_firehose_en", None) - assert ( - method is not None - ), f"Method stream_posts_firehose_en does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"stream_posts_firehose_en is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_firehose_en should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose_en" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_firehose_en_return_annotation(self): - """Test that stream_posts_firehose_en has proper return type annotation.""" - method = getattr(TweetsClient, "stream_posts_firehose_en") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose_en should have return type annotation" - - - def test_stream_posts_sample_exists(self): - """Test that stream_posts_sample method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "stream_posts_sample", None) - assert ( - method is not None - ), f"Method stream_posts_sample does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"stream_posts_sample is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_sample should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_sample" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_sample_return_annotation(self): - """Test that stream_posts_sample has proper return type annotation.""" - method = getattr(TweetsClient, "stream_posts_sample") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_sample should have return type annotation" - - - def test_get_rules_exists(self): - """Test that get_rules method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_rules", None) - assert method is not None, f"Method get_rules does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_rules is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"get_rules should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_rules" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "ids", - "max_results", - "pagination_token", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_rules_return_annotation(self): - """Test that get_rules has proper return type annotation.""" - method = getattr(TweetsClient, "get_rules") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_rules should have return type annotation" - - - def test_get_rules_pagination_params(self): - """Test that get_rules has pagination parameters.""" - method = getattr(TweetsClient, "get_rules") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_rules should have pagination parameters" - - - def test_update_rules_exists(self): - """Test that update_rules method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "update_rules", None) - assert method is not None, f"Method update_rules does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"update_rules is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"update_rules should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from update_rules" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "dry_run", - "delete_all", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_update_rules_return_annotation(self): - """Test that update_rules has proper return type annotation.""" - method = getattr(TweetsClient, "update_rules") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method update_rules should have return type annotation" - - - def test_get_spaces_buyers_exists(self): - """Test that get_spaces_buyers method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_spaces_buyers", None) - assert ( - method is not None - ), f"Method get_spaces_buyers does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_spaces_buyers is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_spaces_buyers should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_spaces_buyers" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "pagination_token", - "max_results", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_spaces_buyers_return_annotation(self): - """Test that get_spaces_buyers has proper return type annotation.""" - method = getattr(TweetsClient, "get_spaces_buyers") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_spaces_buyers should have return type annotation" - - - def test_get_spaces_buyers_pagination_params(self): - """Test that get_spaces_buyers has pagination parameters.""" - method = getattr(TweetsClient, "get_spaces_buyers") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_spaces_buyers should have pagination parameters" - - - def test_get_posts_by_ids_exists(self): - """Test that get_posts_by_ids method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_posts_by_ids", None) - assert ( - method is not None - ), f"Method get_posts_by_ids does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_posts_by_ids is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_posts_by_ids should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "ids", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_posts_by_ids" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_posts_by_ids_return_annotation(self): - """Test that get_posts_by_ids has proper return type annotation.""" - method = getattr(TweetsClient, "get_posts_by_ids") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_posts_by_ids should have return type annotation" - - - def test_create_posts_exists(self): - """Test that create_posts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "create_posts", None) - assert method is not None, f"Method create_posts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"create_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"create_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from create_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_create_posts_return_annotation(self): - """Test that create_posts has proper return type annotation.""" - method = getattr(TweetsClient, "create_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method create_posts should have return type annotation" - - - def test_get_users_timeline_exists(self): - """Test that get_users_timeline method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_users_timeline", None) - assert ( - method is not None - ), f"Method get_users_timeline does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_users_timeline is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_timeline should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_users_timeline" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "since_id", - "until_id", - "max_results", - "pagination_token", - "exclude", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_users_timeline_return_annotation(self): - """Test that get_users_timeline has proper return type annotation.""" - method = getattr(TweetsClient, "get_users_timeline") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_timeline should have return type annotation" - - - def test_get_users_timeline_pagination_params(self): - """Test that get_users_timeline has pagination parameters.""" - method = getattr(TweetsClient, "get_users_timeline") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_timeline should have pagination parameters" - - - def test_get_users_mentions_exists(self): - """Test that get_users_mentions method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_users_mentions", None) - assert ( - method is not None - ), f"Method get_users_mentions does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_users_mentions is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_mentions should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_users_mentions" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "since_id", - "until_id", - "max_results", - "pagination_token", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_users_mentions_return_annotation(self): - """Test that get_users_mentions has proper return type annotation.""" - method = getattr(TweetsClient, "get_users_mentions") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_mentions should have return type annotation" - - - def test_get_users_mentions_pagination_params(self): - """Test that get_users_mentions has pagination parameters.""" - method = getattr(TweetsClient, "get_users_mentions") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_mentions should have pagination parameters" - - - def test_get_insights_historical_exists(self): - """Test that get_insights_historical method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_insights_historical", None) - assert ( - method is not None - ), f"Method get_insights_historical does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_insights_historical is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_insights_historical should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "tweet_ids", - "end_time", - "start_time", - "granularity", - "requested_metrics", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_insights_historical" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_insights_historical_return_annotation(self): - """Test that get_insights_historical has proper return type annotation.""" - method = getattr(TweetsClient, "get_insights_historical") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_insights_historical should have return type annotation" - - - def test_get_posts_counts_recent_exists(self): - """Test that get_posts_counts_recent method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_posts_counts_recent", None) - assert ( - method is not None - ), f"Method get_posts_counts_recent does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_posts_counts_recent is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_posts_counts_recent should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "query", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_posts_counts_recent" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "start_time", - "end_time", - "since_id", - "until_id", - "next_token", - "pagination_token", - "granularity", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_posts_counts_recent_return_annotation(self): - """Test that get_posts_counts_recent has proper return type annotation.""" - method = getattr(TweetsClient, "get_posts_counts_recent") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_posts_counts_recent should have return type annotation" - - - def test_stream_posts_firehose_ko_exists(self): - """Test that stream_posts_firehose_ko method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "stream_posts_firehose_ko", None) - assert ( - method is not None - ), f"Method stream_posts_firehose_ko does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"stream_posts_firehose_ko is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_firehose_ko should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose_ko" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_firehose_ko_return_annotation(self): - """Test that stream_posts_firehose_ko has proper return type annotation.""" - method = getattr(TweetsClient, "stream_posts_firehose_ko") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose_ko should have return type annotation" - - - def test_get_posts_analytics_exists(self): - """Test that get_posts_analytics method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_posts_analytics", None) - assert ( - method is not None - ), f"Method get_posts_analytics does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_posts_analytics is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_posts_analytics should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "ids", - "end_time", - "start_time", - "granularity", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_posts_analytics" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_posts_analytics_return_annotation(self): - """Test that get_posts_analytics has proper return type annotation.""" - method = getattr(TweetsClient, "get_posts_analytics") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_posts_analytics should have return type annotation" - - - def test_get_rule_counts_exists(self): - """Test that get_rule_counts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_rule_counts", None) - assert ( - method is not None - ), f"Method get_rule_counts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_rule_counts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_rule_counts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_rule_counts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_rule_counts_return_annotation(self): - """Test that get_rule_counts has proper return type annotation.""" - method = getattr(TweetsClient, "get_rule_counts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_rule_counts should have return type annotation" - - - def test_get_posts_quoted_posts_exists(self): - """Test that get_posts_quoted_posts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_posts_quoted_posts", None) - assert ( - method is not None - ), f"Method get_posts_quoted_posts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_posts_quoted_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_posts_quoted_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_posts_quoted_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - "exclude", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_posts_quoted_posts_return_annotation(self): - """Test that get_posts_quoted_posts has proper return type annotation.""" - method = getattr(TweetsClient, "get_posts_quoted_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_posts_quoted_posts should have return type annotation" - - - def test_get_posts_quoted_posts_pagination_params(self): - """Test that get_posts_quoted_posts has pagination parameters.""" - method = getattr(TweetsClient, "get_posts_quoted_posts") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_posts_quoted_posts should have pagination parameters" - - - def test_stream_posts_firehose_exists(self): - """Test that stream_posts_firehose method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "stream_posts_firehose", None) - assert ( - method is not None - ), f"Method stream_posts_firehose does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"stream_posts_firehose is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_firehose should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_firehose_return_annotation(self): - """Test that stream_posts_firehose has proper return type annotation.""" - method = getattr(TweetsClient, "stream_posts_firehose") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose should have return type annotation" - - - def test_get_insights28_hr_exists(self): - """Test that get_insights28_hr method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_insights28_hr", None) - assert ( - method is not None - ), f"Method get_insights28_hr does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_insights28_hr is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_insights28_hr should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "tweet_ids", - "granularity", - "requested_metrics", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_insights28_hr" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_insights28_hr_return_annotation(self): - """Test that get_insights28_hr has proper return type annotation.""" - method = getattr(TweetsClient, "get_insights28_hr") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_insights28_hr should have return type annotation" - - - def test_get_posts_reposts_exists(self): - """Test that get_posts_reposts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_posts_reposts", None) - assert ( - method is not None - ), f"Method get_posts_reposts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_posts_reposts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_posts_reposts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_posts_reposts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_posts_reposts_return_annotation(self): - """Test that get_posts_reposts has proper return type annotation.""" - method = getattr(TweetsClient, "get_posts_reposts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_posts_reposts should have return type annotation" - - - def test_get_posts_reposts_pagination_params(self): - """Test that get_posts_reposts has pagination parameters.""" - method = getattr(TweetsClient, "get_posts_reposts") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_posts_reposts should have pagination parameters" - - - def test_stream_posts_sample10_exists(self): - """Test that stream_posts_sample10 method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "stream_posts_sample10", None) - assert ( - method is not None - ), f"Method stream_posts_sample10 does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"stream_posts_sample10 is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_sample10 should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_sample10" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_sample10_return_annotation(self): - """Test that stream_posts_sample10 has proper return type annotation.""" - method = getattr(TweetsClient, "stream_posts_sample10") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_sample10 should have return type annotation" - - - def test_repost_post_exists(self): - """Test that repost_post method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "repost_post", None) - assert method is not None, f"Method repost_post does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"repost_post is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"repost_post should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from repost_post" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_repost_post_return_annotation(self): - """Test that repost_post has proper return type annotation.""" - method = getattr(TweetsClient, "repost_post") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method repost_post should have return type annotation" - - - def test_search_posts_all_exists(self): - """Test that search_posts_all method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "search_posts_all", None) - assert ( - method is not None - ), f"Method search_posts_all does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"search_posts_all is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"search_posts_all should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "query", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from search_posts_all" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "start_time", - "end_time", - "since_id", - "until_id", - "max_results", - "next_token", - "pagination_token", - "sort_order", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_search_posts_all_return_annotation(self): - """Test that search_posts_all has proper return type annotation.""" - method = getattr(TweetsClient, "search_posts_all") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method search_posts_all should have return type annotation" - - - def test_search_posts_all_pagination_params(self): - """Test that search_posts_all has pagination parameters.""" - method = getattr(TweetsClient, "search_posts_all") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method search_posts_all should have pagination parameters" - - - def test_unrepost_post_exists(self): - """Test that unrepost_post method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "unrepost_post", None) - assert ( - method is not None - ), f"Method unrepost_post does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"unrepost_post is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"unrepost_post should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - "source_tweet_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from unrepost_post" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_unrepost_post_return_annotation(self): - """Test that unrepost_post has proper return type annotation.""" - method = getattr(TweetsClient, "unrepost_post") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method unrepost_post should have return type annotation" - - - def test_stream_posts_exists(self): - """Test that stream_posts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "stream_posts", None) - assert method is not None, f"Method stream_posts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"stream_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"stream_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_return_annotation(self): - """Test that stream_posts has proper return type annotation.""" - method = getattr(TweetsClient, "stream_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts should have return type annotation" - - - def test_like_post_exists(self): - """Test that like_post method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "like_post", None) - assert method is not None, f"Method like_post does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"like_post is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"like_post should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from like_post" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_like_post_return_annotation(self): - """Test that like_post has proper return type annotation.""" - method = getattr(TweetsClient, "like_post") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method like_post should have return type annotation" - - - def test_get_posts_counts_all_exists(self): - """Test that get_posts_counts_all method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_posts_counts_all", None) - assert ( - method is not None - ), f"Method get_posts_counts_all does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_posts_counts_all is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_posts_counts_all should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "query", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_posts_counts_all" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "start_time", - "end_time", - "since_id", - "until_id", - "next_token", - "pagination_token", - "granularity", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_posts_counts_all_return_annotation(self): - """Test that get_posts_counts_all has proper return type annotation.""" - method = getattr(TweetsClient, "get_posts_counts_all") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_posts_counts_all should have return type annotation" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "unlike_post", - "search_posts_recent", - "get_posts_by_id", - "delete_posts", - "get_lists_posts", - "get_users_posts", - "stream_posts_firehose_pt", - "get_spaces_posts", - "stream_posts_firehose_ja", - "hide_posts_reply", - "get_users_liked_posts", - "stream_posts_firehose_en", - "stream_posts_sample", - "get_rules", - "update_rules", - "get_spaces_buyers", - "get_posts_by_ids", - "create_posts", - "get_users_timeline", - "get_users_mentions", - "get_insights_historical", - "get_posts_counts_recent", - "stream_posts_firehose_ko", - "get_posts_analytics", - "get_rule_counts", - "get_posts_quoted_posts", - "stream_posts_firehose", - "get_insights28_hr", - "get_posts_reposts", - "stream_posts_sample10", - "repost_post", - "search_posts_all", - "unrepost_post", - "stream_posts", - "like_post", - "get_posts_counts_all", - ] - for expected_method in expected_methods: - assert hasattr( - TweetsClient, expected_method - ), f"Expected method '{expected_method}' not found on TweetsClient" - assert callable( - getattr(TweetsClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/tests/usage/test_contracts.py b/xdk/python/tests/usage/test_contracts.py index 981c1657..eaa18806 100644 --- a/xdk/python/tests/usage/test_contracts.py +++ b/xdk/python/tests/usage/test_contracts.py @@ -1,8 +1,8 @@ """ -Auto-generated contract tests for Usage client. +Auto-generated contract tests for {"class_name": "Usage", "display_name": "usage", "import_name": "usage", "original": ["usage"], "property_name": "usage"} client. This module contains tests that validate the request/response contracts -of the Usage client against the OpenAPI specification. +of the {"class_name": "Usage", "display_name": "usage", "import_name": "usage", "original": ["usage"], "property_name": "usage"} client against the OpenAPI specification. Generated automatically - do not edit manually. """ @@ -24,8 +24,8 @@ def setup_class(self): self.usage_client = getattr(self.client, "usage") - def test_get_usage_request_structure(self): - """Test get_usage request structure.""" + def test_get_request_structure(self): + """Test get request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -41,7 +41,7 @@ def test_get_usage_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.usage_client, "get_usage") + method = getattr(self.usage_client, "get") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -60,12 +60,12 @@ def test_get_usage_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_usage: {e}") + pytest.fail(f"Contract test failed for get: {e}") - def test_get_usage_required_parameters(self): - """Test that get_usage handles parameters correctly.""" - method = getattr(self.usage_client, "get_usage") + def test_get_required_parameters(self): + """Test that get handles parameters correctly.""" + method = getattr(self.usage_client, "get") # No required parameters, method should be callable without args with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -79,8 +79,8 @@ def test_get_usage_required_parameters(self): pytest.fail(f"Method with no required params should be callable: {e}") - def test_get_usage_response_structure(self): - """Test get_usage response structure validation.""" + def test_get_response_structure(self): + """Test get response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -95,7 +95,7 @@ def test_get_usage_response_structure(self): kwargs = {} # Add request body if required # Call method and verify response structure - method = getattr(self.usage_client, "get_usage") + method = getattr(self.usage_client, "get") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed diff --git a/xdk/python/tests/usage/test_generic.py b/xdk/python/tests/usage/test_generic.py index b49fe951..3cf2d6e4 100644 --- a/xdk/python/tests/usage/test_generic.py +++ b/xdk/python/tests/usage/test_generic.py @@ -1,5 +1,5 @@ """ -Auto-generated generic tests for Usage client. +Auto-generated generic tests for {"class_name": "Usage", "display_name": "usage", "import_name": "usage", "original": ["usage"], "property_name": "usage"} client. This module contains general tests that validate the overall client functionality, imports, and error handling that don't need to be diff --git a/xdk/python/tests/usage/test_structure.py b/xdk/python/tests/usage/test_structure.py index 6f99fdf7..5249aa06 100644 --- a/xdk/python/tests/usage/test_structure.py +++ b/xdk/python/tests/usage/test_structure.py @@ -1,8 +1,8 @@ """ -Auto-generated structural tests for Usage client. +Auto-generated structural tests for {"class_name": "Usage", "display_name": "usage", "import_name": "usage", "original": ["usage"], "property_name": "usage"} client. This module contains tests that validate the structure and API surface -of the Usage client. These tests ensure that all expected methods +of the {"class_name": "Usage", "display_name": "usage", "import_name": "usage", "original": ["usage"], "property_name": "usage"} client. These tests ensure that all expected methods exist and have the correct signatures. Generated automatically - do not edit manually. @@ -25,18 +25,18 @@ def setup_class(self): self.usage_client = getattr(self.client, "usage") - def test_get_usage_exists(self): - """Test that get_usage method exists with correct signature.""" + def test_get_exists(self): + """Test that get method exists with correct signature.""" # Check method exists - method = getattr(UsageClient, "get_usage", None) - assert method is not None, f"Method get_usage does not exist on UsageClient" + method = getattr(UsageClient, "get", None) + assert method is not None, f"Method get does not exist on UsageClient" # Check method is callable - assert callable(method), f"get_usage is not callable" + assert callable(method), f"get is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"get_usage should have at least 'self' parameter" + assert len(params) >= 1, f"get should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -45,7 +45,7 @@ def test_get_usage_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_usage" + ), f"Required parameter '{required_param}' missing from get" # Check optional parameters have defaults (excluding 'self') optional_params = [ "days", @@ -58,20 +58,20 @@ def test_get_usage_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_usage_return_annotation(self): - """Test that get_usage has proper return type annotation.""" - method = getattr(UsageClient, "get_usage") + def test_get_return_annotation(self): + """Test that get has proper return type annotation.""" + method = getattr(UsageClient, "get") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_usage should have return type annotation" + ), f"Method get should have return type annotation" def test_all_expected_methods_exist(self): """Test that all expected methods exist on the client.""" expected_methods = [ - "get_usage", + "get", ] for expected_method in expected_methods: assert hasattr( diff --git a/xdk/python/tests/users/test_contracts.py b/xdk/python/tests/users/test_contracts.py index 37b1cd43..99b8e3c5 100644 --- a/xdk/python/tests/users/test_contracts.py +++ b/xdk/python/tests/users/test_contracts.py @@ -1,8 +1,8 @@ """ -Auto-generated contract tests for Users client. +Auto-generated contract tests for {"class_name": "Users", "display_name": "users", "import_name": "users", "original": ["users"], "property_name": "users"} client. This module contains tests that validate the request/response contracts -of the Users client against the OpenAPI specification. +of the {"class_name": "Users", "display_name": "users", "import_name": "users", "original": ["users"], "property_name": "users"} client against the OpenAPI specification. Generated automatically - do not edit manually. """ @@ -24,8 +24,8 @@ def setup_class(self): self.users_client = getattr(self.client, "users") - def test_get_lists_followers_request_structure(self): - """Test get_lists_followers request structure.""" + def test_get_followed_lists_request_structure(self): + """Test get_followed_lists request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -42,7 +42,7 @@ def test_get_lists_followers_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_lists_followers") + method = getattr(self.users_client, "get_followed_lists") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -52,7 +52,7 @@ def test_get_lists_followers_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/lists/{id}/followers" + expected_path = "/2/users/{id}/followed_lists" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -61,12 +61,12 @@ def test_get_lists_followers_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_lists_followers: {e}") + pytest.fail(f"Contract test failed for get_followed_lists: {e}") - def test_get_lists_followers_required_parameters(self): - """Test that get_lists_followers handles parameters correctly.""" - method = getattr(self.users_client, "get_lists_followers") + def test_get_followed_lists_required_parameters(self): + """Test that get_followed_lists handles parameters correctly.""" + method = getattr(self.users_client, "get_followed_lists") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -80,8 +80,8 @@ def test_get_lists_followers_required_parameters(self): method() - def test_get_lists_followers_response_structure(self): - """Test get_lists_followers response structure validation.""" + def test_get_followed_lists_response_structure(self): + """Test get_followed_lists response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -97,7 +97,7 @@ def test_get_lists_followers_response_structure(self): kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_lists_followers") + method = getattr(self.users_client, "get_followed_lists") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -109,8 +109,8 @@ def test_get_lists_followers_response_structure(self): ) - def test_get_users_muting_request_structure(self): - """Test get_users_muting request structure.""" + def test_get_list_memberships_request_structure(self): + """Test get_list_memberships request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -127,7 +127,7 @@ def test_get_users_muting_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_users_muting") + method = getattr(self.users_client, "get_list_memberships") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -137,7 +137,7 @@ def test_get_users_muting_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/muting" + expected_path = "/2/users/{id}/list_memberships" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -146,12 +146,12 @@ def test_get_users_muting_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_muting: {e}") + pytest.fail(f"Contract test failed for get_list_memberships: {e}") - def test_get_users_muting_required_parameters(self): - """Test that get_users_muting handles parameters correctly.""" - method = getattr(self.users_client, "get_users_muting") + def test_get_list_memberships_required_parameters(self): + """Test that get_list_memberships handles parameters correctly.""" + method = getattr(self.users_client, "get_list_memberships") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -165,8 +165,8 @@ def test_get_users_muting_required_parameters(self): method() - def test_get_users_muting_response_structure(self): - """Test get_users_muting response structure validation.""" + def test_get_list_memberships_response_structure(self): + """Test get_list_memberships response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -182,7 +182,7 @@ def test_get_users_muting_response_structure(self): kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_users_muting") + method = getattr(self.users_client, "get_list_memberships") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -194,8 +194,8 @@ def test_get_users_muting_response_structure(self): ) - def test_mute_user_request_structure(self): - """Test mute_user request structure.""" + def test_get_reposts_of_me_request_structure(self): + """Test get_reposts_of_me request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -204,29 +204,108 @@ def test_mute_user_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response + # Prepare test parameters + kwargs = {} + # Add required parameters + # Add request body if required + # Call the method + try: + method = getattr(self.users_client, "get_reposts_of_me") + result = method(**kwargs) + # Verify the request was made + mock_session.get.assert_called_once() + # Verify request structure + call_args = mock_session.get.call_args + # Check URL structure + called_url = ( + call_args[0][0] if call_args[0] else call_args[1].get("url", "") + ) + expected_path = "/2/users/reposts_of_me" + assert expected_path.replace("{", "").replace( + "}", "" + ) in called_url or any( + param in called_url for param in ["test_", "42"] + ), f"URL should contain path template elements: {called_url}" + # Verify response structure + assert result is not None, "Method should return a result" + except Exception as e: + pytest.fail(f"Contract test failed for get_reposts_of_me: {e}") + + + def test_get_reposts_of_me_required_parameters(self): + """Test that get_reposts_of_me handles parameters correctly.""" + method = getattr(self.users_client, "get_reposts_of_me") + # No required parameters, method should be callable without args + with patch.object(self.client, "session") as mock_session: + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = {} + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + try: + method() + except Exception as e: + pytest.fail(f"Method with no required params should be callable: {e}") + + + def test_get_reposts_of_me_response_structure(self): + """Test get_reposts_of_me response structure validation.""" + with patch.object(self.client, "session") as mock_session: + # Create mock response with expected structure + mock_response_data = { + "data": None, + } + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = mock_response_data + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + # Prepare minimal valid parameters + kwargs = {} + # Add request body if required + # Call method and verify response structure + method = getattr(self.users_client, "get_reposts_of_me") + result = method(**kwargs) + # Verify response object has expected attributes + # Optional field - just check it doesn't cause errors if accessed + try: + getattr(result, "data", None) + except Exception as e: + pytest.fail( + f"Accessing optional field 'data' should not cause errors: {e}" + ) + + + def test_get_owned_lists_request_structure(self): + """Test get_owned_lists request structure.""" + # Mock the session to capture request details + with patch.object(self.client, "session") as mock_session: + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "data": None, + } + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters kwargs["id"] = "test_value" # Add request body if required - # Import and create proper request model instance - from xdk.users.models import MuteUserRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = MuteUserRequest() # Call the method try: - method = getattr(self.users_client, "mute_user") + method = getattr(self.users_client, "get_owned_lists") result = method(**kwargs) # Verify the request was made - mock_session.post.assert_called_once() + mock_session.get.assert_called_once() # Verify request structure - call_args = mock_session.post.call_args + call_args = mock_session.get.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/muting" + expected_path = "/2/users/{id}/owned_lists" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -235,12 +314,12 @@ def test_mute_user_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for mute_user: {e}") + pytest.fail(f"Contract test failed for get_owned_lists: {e}") - def test_mute_user_required_parameters(self): - """Test that mute_user handles parameters correctly.""" - method = getattr(self.users_client, "mute_user") + def test_get_owned_lists_required_parameters(self): + """Test that get_owned_lists handles parameters correctly.""" + method = getattr(self.users_client, "get_owned_lists") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -248,14 +327,14 @@ def test_mute_user_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_mute_user_response_structure(self): - """Test mute_user response structure validation.""" + def test_get_owned_lists_response_structure(self): + """Test get_owned_lists response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -265,17 +344,13 @@ def test_mute_user_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" # Add request body if required - # Import and create proper request model instance - from xdk.users.models import MuteUserRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = MuteUserRequest() # Call method and verify response structure - method = getattr(self.users_client, "mute_user") + method = getattr(self.users_client, "get_owned_lists") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -287,8 +362,8 @@ def test_mute_user_response_structure(self): ) - def test_get_my_user_request_structure(self): - """Test get_my_user request structure.""" + def test_get_posts_request_structure(self): + """Test get_posts request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -301,10 +376,11 @@ def test_get_my_user_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters + kwargs["id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_my_user") + method = getattr(self.users_client, "get_posts") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -314,7 +390,7 @@ def test_get_my_user_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/me" + expected_path = "/2/users/{id}/tweets" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -323,27 +399,282 @@ def test_get_my_user_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_my_user: {e}") + pytest.fail(f"Contract test failed for get_posts: {e}") - def test_get_my_user_required_parameters(self): - """Test that get_my_user handles parameters correctly.""" - method = getattr(self.users_client, "get_my_user") - # No required parameters, method should be callable without args + def test_get_posts_required_parameters(self): + """Test that get_posts handles parameters correctly.""" + method = getattr(self.users_client, "get_posts") + # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: + # Mock a 400 response (typical for missing required parameters) + mock_response = Mock() + mock_response.status_code = 400 + mock_response.json.return_value = {"error": "Missing required parameters"} + mock_response.raise_for_status.side_effect = Exception("Bad Request") + mock_session.get.return_value = mock_response + # Call without required parameters should either raise locally or via server response + with pytest.raises((TypeError, ValueError, Exception)): + method() + + + def test_get_posts_response_structure(self): + """Test get_posts response structure validation.""" + with patch.object(self.client, "session") as mock_session: + # Create mock response with expected structure + mock_response_data = { + "data": None, + } mock_response = Mock() mock_response.status_code = 200 - mock_response.json.return_value = {} + mock_response.json.return_value = mock_response_data + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + # Prepare minimal valid parameters + kwargs = {} + kwargs["id"] = "test" + # Add request body if required + # Call method and verify response structure + method = getattr(self.users_client, "get_posts") + result = method(**kwargs) + # Verify response object has expected attributes + # Optional field - just check it doesn't cause errors if accessed + try: + getattr(result, "data", None) + except Exception as e: + pytest.fail( + f"Accessing optional field 'data' should not cause errors: {e}" + ) + + + def test_get_liked_posts_request_structure(self): + """Test get_liked_posts request structure.""" + # Mock the session to capture request details + with patch.object(self.client, "session") as mock_session: + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "data": None, + } + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + # Prepare test parameters + kwargs = {} + # Add required parameters + kwargs["id"] = "test_value" + # Add request body if required + # Call the method + try: + method = getattr(self.users_client, "get_liked_posts") + result = method(**kwargs) + # Verify the request was made + mock_session.get.assert_called_once() + # Verify request structure + call_args = mock_session.get.call_args + # Check URL structure + called_url = ( + call_args[0][0] if call_args[0] else call_args[1].get("url", "") + ) + expected_path = "/2/users/{id}/liked_tweets" + assert expected_path.replace("{", "").replace( + "}", "" + ) in called_url or any( + param in called_url for param in ["test_", "42"] + ), f"URL should contain path template elements: {called_url}" + # Verify response structure + assert result is not None, "Method should return a result" + except Exception as e: + pytest.fail(f"Contract test failed for get_liked_posts: {e}") + + + def test_get_liked_posts_required_parameters(self): + """Test that get_liked_posts handles parameters correctly.""" + method = getattr(self.users_client, "get_liked_posts") + # Test with missing required parameters - mock the request to avoid network calls + with patch.object(self.client, "session") as mock_session: + # Mock a 400 response (typical for missing required parameters) + mock_response = Mock() + mock_response.status_code = 400 + mock_response.json.return_value = {"error": "Missing required parameters"} + mock_response.raise_for_status.side_effect = Exception("Bad Request") + mock_session.get.return_value = mock_response + # Call without required parameters should either raise locally or via server response + with pytest.raises((TypeError, ValueError, Exception)): + method() + + + def test_get_liked_posts_response_structure(self): + """Test get_liked_posts response structure validation.""" + with patch.object(self.client, "session") as mock_session: + # Create mock response with expected structure + mock_response_data = { + "data": None, + } + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = mock_response_data + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + # Prepare minimal valid parameters + kwargs = {} + kwargs["id"] = "test" + # Add request body if required + # Call method and verify response structure + method = getattr(self.users_client, "get_liked_posts") + result = method(**kwargs) + # Verify response object has expected attributes + # Optional field - just check it doesn't cause errors if accessed + try: + getattr(result, "data", None) + except Exception as e: + pytest.fail( + f"Accessing optional field 'data' should not cause errors: {e}" + ) + + + def test_get_timeline_request_structure(self): + """Test get_timeline request structure.""" + # Mock the session to capture request details + with patch.object(self.client, "session") as mock_session: + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "data": None, + } mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response + # Prepare test parameters + kwargs = {} + # Add required parameters + kwargs["id"] = "test_value" + # Add request body if required + # Call the method try: + method = getattr(self.users_client, "get_timeline") + result = method(**kwargs) + # Verify the request was made + mock_session.get.assert_called_once() + # Verify request structure + call_args = mock_session.get.call_args + # Check URL structure + called_url = ( + call_args[0][0] if call_args[0] else call_args[1].get("url", "") + ) + expected_path = "/2/users/{id}/timelines/reverse_chronological" + assert expected_path.replace("{", "").replace( + "}", "" + ) in called_url or any( + param in called_url for param in ["test_", "42"] + ), f"URL should contain path template elements: {called_url}" + # Verify response structure + assert result is not None, "Method should return a result" + except Exception as e: + pytest.fail(f"Contract test failed for get_timeline: {e}") + + + def test_get_timeline_required_parameters(self): + """Test that get_timeline handles parameters correctly.""" + method = getattr(self.users_client, "get_timeline") + # Test with missing required parameters - mock the request to avoid network calls + with patch.object(self.client, "session") as mock_session: + # Mock a 400 response (typical for missing required parameters) + mock_response = Mock() + mock_response.status_code = 400 + mock_response.json.return_value = {"error": "Missing required parameters"} + mock_response.raise_for_status.side_effect = Exception("Bad Request") + mock_session.get.return_value = mock_response + # Call without required parameters should either raise locally or via server response + with pytest.raises((TypeError, ValueError, Exception)): method() + + + def test_get_timeline_response_structure(self): + """Test get_timeline response structure validation.""" + with patch.object(self.client, "session") as mock_session: + # Create mock response with expected structure + mock_response_data = { + "data": None, + } + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = mock_response_data + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + # Prepare minimal valid parameters + kwargs = {} + kwargs["id"] = "test" + # Add request body if required + # Call method and verify response structure + method = getattr(self.users_client, "get_timeline") + result = method(**kwargs) + # Verify response object has expected attributes + # Optional field - just check it doesn't cause errors if accessed + try: + getattr(result, "data", None) except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") + pytest.fail( + f"Accessing optional field 'data' should not cause errors: {e}" + ) + + + def test_get_by_usernames_request_structure(self): + """Test get_by_usernames request structure.""" + # Mock the session to capture request details + with patch.object(self.client, "session") as mock_session: + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "data": None, + } + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + # Prepare test parameters + kwargs = {} + # Add required parameters + kwargs["usernames"] = ["test_item"] + # Add request body if required + # Call the method + try: + method = getattr(self.users_client, "get_by_usernames") + result = method(**kwargs) + # Verify the request was made + mock_session.get.assert_called_once() + # Verify request structure + call_args = mock_session.get.call_args + # Check URL structure + called_url = ( + call_args[0][0] if call_args[0] else call_args[1].get("url", "") + ) + expected_path = "/2/users/by" + assert expected_path.replace("{", "").replace( + "}", "" + ) in called_url or any( + param in called_url for param in ["test_", "42"] + ), f"URL should contain path template elements: {called_url}" + # Verify response structure + assert result is not None, "Method should return a result" + except Exception as e: + pytest.fail(f"Contract test failed for get_by_usernames: {e}") + + + def test_get_by_usernames_required_parameters(self): + """Test that get_by_usernames handles parameters correctly.""" + method = getattr(self.users_client, "get_by_usernames") + # Test with missing required parameters - mock the request to avoid network calls + with patch.object(self.client, "session") as mock_session: + # Mock a 400 response (typical for missing required parameters) + mock_response = Mock() + mock_response.status_code = 400 + mock_response.json.return_value = {"error": "Missing required parameters"} + mock_response.raise_for_status.side_effect = Exception("Bad Request") + mock_session.get.return_value = mock_response + # Call without required parameters should either raise locally or via server response + with pytest.raises((TypeError, ValueError, Exception)): + method() - def test_get_my_user_response_structure(self): - """Test get_my_user response structure validation.""" + def test_get_by_usernames_response_structure(self): + """Test get_by_usernames response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -356,9 +687,10 @@ def test_get_my_user_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} + kwargs["usernames"] = ["test"] # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_my_user") + method = getattr(self.users_client, "get_by_usernames") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -370,8 +702,8 @@ def test_get_my_user_response_structure(self): ) - def test_get_users_reposts_of_me_request_structure(self): - """Test get_users_reposts_of_me request structure.""" + def test_get_mentions_request_structure(self): + """Test get_mentions request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -384,10 +716,11 @@ def test_get_users_reposts_of_me_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters + kwargs["id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_users_reposts_of_me") + method = getattr(self.users_client, "get_mentions") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -397,7 +730,7 @@ def test_get_users_reposts_of_me_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/reposts_of_me" + expected_path = "/2/users/{id}/mentions" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -406,27 +739,27 @@ def test_get_users_reposts_of_me_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_reposts_of_me: {e}") + pytest.fail(f"Contract test failed for get_mentions: {e}") - def test_get_users_reposts_of_me_required_parameters(self): - """Test that get_users_reposts_of_me handles parameters correctly.""" - method = getattr(self.users_client, "get_users_reposts_of_me") - # No required parameters, method should be callable without args + def test_get_mentions_required_parameters(self): + """Test that get_mentions handles parameters correctly.""" + method = getattr(self.users_client, "get_mentions") + # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: + # Mock a 400 response (typical for missing required parameters) mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None + mock_response.status_code = 400 + mock_response.json.return_value = {"error": "Missing required parameters"} + mock_response.raise_for_status.side_effect = Exception("Bad Request") mock_session.get.return_value = mock_response - try: + # Call without required parameters should either raise locally or via server response + with pytest.raises((TypeError, ValueError, Exception)): method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - def test_get_users_reposts_of_me_response_structure(self): - """Test get_users_reposts_of_me response structure validation.""" + def test_get_mentions_response_structure(self): + """Test get_mentions response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -439,9 +772,10 @@ def test_get_users_reposts_of_me_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} + kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_users_reposts_of_me") + method = getattr(self.users_client, "get_mentions") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -453,8 +787,8 @@ def test_get_users_reposts_of_me_response_structure(self): ) - def test_search_users_request_structure(self): - """Test search_users request structure.""" + def test_search_request_structure(self): + """Test search request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -471,7 +805,7 @@ def test_search_users_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.users_client, "search_users") + method = getattr(self.users_client, "search") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -490,12 +824,12 @@ def test_search_users_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for search_users: {e}") + pytest.fail(f"Contract test failed for search: {e}") - def test_search_users_required_parameters(self): - """Test that search_users handles parameters correctly.""" - method = getattr(self.users_client, "search_users") + def test_search_required_parameters(self): + """Test that search handles parameters correctly.""" + method = getattr(self.users_client, "search") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -509,8 +843,8 @@ def test_search_users_required_parameters(self): method() - def test_search_users_response_structure(self): - """Test search_users response structure validation.""" + def test_search_response_structure(self): + """Test search response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -526,7 +860,7 @@ def test_search_users_response_structure(self): kwargs["query"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "search_users") + method = getattr(self.users_client, "search") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -538,8 +872,8 @@ def test_search_users_response_structure(self): ) - def test_get_users_by_ids_request_structure(self): - """Test get_users_by_ids request structure.""" + def test_get_muting_request_structure(self): + """Test get_muting request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -552,11 +886,11 @@ def test_get_users_by_ids_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["ids"] = ["test_item"] + kwargs["id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_users_by_ids") + method = getattr(self.users_client, "get_muting") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -566,7 +900,7 @@ def test_get_users_by_ids_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users" + expected_path = "/2/users/{id}/muting" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -575,12 +909,12 @@ def test_get_users_by_ids_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_by_ids: {e}") + pytest.fail(f"Contract test failed for get_muting: {e}") - def test_get_users_by_ids_required_parameters(self): - """Test that get_users_by_ids handles parameters correctly.""" - method = getattr(self.users_client, "get_users_by_ids") + def test_get_muting_required_parameters(self): + """Test that get_muting handles parameters correctly.""" + method = getattr(self.users_client, "get_muting") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -594,8 +928,8 @@ def test_get_users_by_ids_required_parameters(self): method() - def test_get_users_by_ids_response_structure(self): - """Test get_users_by_ids response structure validation.""" + def test_get_muting_response_structure(self): + """Test get_muting response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -608,10 +942,10 @@ def test_get_users_by_ids_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["ids"] = ["test"] + kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_users_by_ids") + method = getattr(self.users_client, "get_muting") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -623,8 +957,8 @@ def test_get_users_by_ids_response_structure(self): ) - def test_get_users_blocking_request_structure(self): - """Test get_users_blocking request structure.""" + def test_mute_user_request_structure(self): + """Test mute_user request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -633,25 +967,29 @@ def test_get_users_blocking_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters kwargs["id"] = "test_value" # Add request body if required + # Import and create proper request model instance + from xdk.users.models import MuteUserRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = MuteUserRequest() # Call the method try: - method = getattr(self.users_client, "get_users_blocking") + method = getattr(self.users_client, "mute_user") result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.post.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.post.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/blocking" + expected_path = "/2/users/{id}/muting" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -660,12 +998,12 @@ def test_get_users_blocking_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_blocking: {e}") + pytest.fail(f"Contract test failed for mute_user: {e}") - def test_get_users_blocking_required_parameters(self): - """Test that get_users_blocking handles parameters correctly.""" - method = getattr(self.users_client, "get_users_blocking") + def test_mute_user_required_parameters(self): + """Test that mute_user handles parameters correctly.""" + method = getattr(self.users_client, "mute_user") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -673,14 +1011,14 @@ def test_get_users_blocking_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_get_users_blocking_response_structure(self): - """Test get_users_blocking response structure validation.""" + def test_mute_user_response_structure(self): + """Test mute_user response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -690,13 +1028,17 @@ def test_get_users_blocking_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" # Add request body if required + # Import and create proper request model instance + from xdk.users.models import MuteUserRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = MuteUserRequest() # Call method and verify response structure - method = getattr(self.users_client, "get_users_blocking") + method = getattr(self.users_client, "mute_user") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -708,8 +1050,8 @@ def test_get_users_blocking_response_structure(self): ) - def test_block_users_dms_request_structure(self): - """Test block_users_dms request structure.""" + def test_unblock_dms_request_structure(self): + """Test unblock_dms request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -726,7 +1068,7 @@ def test_block_users_dms_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.users_client, "block_users_dms") + method = getattr(self.users_client, "unblock_dms") result = method(**kwargs) # Verify the request was made mock_session.post.assert_called_once() @@ -736,7 +1078,7 @@ def test_block_users_dms_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/dm/block" + expected_path = "/2/users/{id}/dm/unblock" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -745,12 +1087,12 @@ def test_block_users_dms_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for block_users_dms: {e}") + pytest.fail(f"Contract test failed for unblock_dms: {e}") - def test_block_users_dms_required_parameters(self): - """Test that block_users_dms handles parameters correctly.""" - method = getattr(self.users_client, "block_users_dms") + def test_unblock_dms_required_parameters(self): + """Test that unblock_dms handles parameters correctly.""" + method = getattr(self.users_client, "unblock_dms") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -764,8 +1106,8 @@ def test_block_users_dms_required_parameters(self): method() - def test_block_users_dms_response_structure(self): - """Test block_users_dms response structure validation.""" + def test_unblock_dms_response_structure(self): + """Test unblock_dms response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -781,7 +1123,7 @@ def test_block_users_dms_response_structure(self): kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "block_users_dms") + method = getattr(self.users_client, "unblock_dms") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -793,8 +1135,8 @@ def test_block_users_dms_response_structure(self): ) - def test_get_users_by_username_request_structure(self): - """Test get_users_by_username request structure.""" + def test_unmute_user_request_structure(self): + """Test unmute_user request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -803,25 +1145,26 @@ def test_get_users_by_username_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["username"] = "test_username" + kwargs["source_user_id"] = "test_value" + kwargs["target_user_id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_users_by_username") + method = getattr(self.users_client, "unmute_user") result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.delete.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.delete.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/by/username/{username}" + expected_path = "/2/users/{source_user_id}/muting/{target_user_id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -830,12 +1173,12 @@ def test_get_users_by_username_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_by_username: {e}") + pytest.fail(f"Contract test failed for unmute_user: {e}") - def test_get_users_by_username_required_parameters(self): - """Test that get_users_by_username handles parameters correctly.""" - method = getattr(self.users_client, "get_users_by_username") + def test_unmute_user_required_parameters(self): + """Test that unmute_user handles parameters correctly.""" + method = getattr(self.users_client, "unmute_user") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -843,14 +1186,14 @@ def test_get_users_by_username_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_get_users_by_username_response_structure(self): - """Test get_users_by_username response structure validation.""" + def test_unmute_user_response_structure(self): + """Test unmute_user response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -860,13 +1203,14 @@ def test_get_users_by_username_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["username"] = "test_value" + kwargs["source_user_id"] = "test" + kwargs["target_user_id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_users_by_username") + method = getattr(self.users_client, "unmute_user") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -878,8 +1222,8 @@ def test_get_users_by_username_response_structure(self): ) - def test_get_users_following_request_structure(self): - """Test get_users_following request structure.""" + def test_get_bookmarks_request_structure(self): + """Test get_bookmarks request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -896,7 +1240,7 @@ def test_get_users_following_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_users_following") + method = getattr(self.users_client, "get_bookmarks") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -906,7 +1250,7 @@ def test_get_users_following_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/following" + expected_path = "/2/users/{id}/bookmarks" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -915,12 +1259,12 @@ def test_get_users_following_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_following: {e}") + pytest.fail(f"Contract test failed for get_bookmarks: {e}") - def test_get_users_following_required_parameters(self): - """Test that get_users_following handles parameters correctly.""" - method = getattr(self.users_client, "get_users_following") + def test_get_bookmarks_required_parameters(self): + """Test that get_bookmarks handles parameters correctly.""" + method = getattr(self.users_client, "get_bookmarks") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -934,8 +1278,8 @@ def test_get_users_following_required_parameters(self): method() - def test_get_users_following_response_structure(self): - """Test get_users_following response structure validation.""" + def test_get_bookmarks_response_structure(self): + """Test get_bookmarks response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -951,7 +1295,7 @@ def test_get_users_following_response_structure(self): kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_users_following") + method = getattr(self.users_client, "get_bookmarks") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -963,8 +1307,8 @@ def test_get_users_following_response_structure(self): ) - def test_follow_user_request_structure(self): - """Test follow_user request structure.""" + def test_get_by_ids_request_structure(self): + """Test get_by_ids request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -973,29 +1317,25 @@ def test_follow_user_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["id"] = "test_value" + kwargs["ids"] = ["test_item"] # Add request body if required - # Import and create proper request model instance - from xdk.users.models import FollowUserRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = FollowUserRequest() # Call the method try: - method = getattr(self.users_client, "follow_user") + method = getattr(self.users_client, "get_by_ids") result = method(**kwargs) # Verify the request was made - mock_session.post.assert_called_once() + mock_session.get.assert_called_once() # Verify request structure - call_args = mock_session.post.call_args + call_args = mock_session.get.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/following" + expected_path = "/2/users" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1004,12 +1344,12 @@ def test_follow_user_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for follow_user: {e}") + pytest.fail(f"Contract test failed for get_by_ids: {e}") - def test_follow_user_required_parameters(self): - """Test that follow_user handles parameters correctly.""" - method = getattr(self.users_client, "follow_user") + def test_get_by_ids_required_parameters(self): + """Test that get_by_ids handles parameters correctly.""" + method = getattr(self.users_client, "get_by_ids") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1017,14 +1357,14 @@ def test_follow_user_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_follow_user_response_structure(self): - """Test follow_user response structure validation.""" + def test_get_by_ids_response_structure(self): + """Test get_by_ids response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1034,17 +1374,13 @@ def test_follow_user_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["id"] = "test" + kwargs["ids"] = ["test"] # Add request body if required - # Import and create proper request model instance - from xdk.users.models import FollowUserRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = FollowUserRequest() # Call method and verify response structure - method = getattr(self.users_client, "follow_user") + method = getattr(self.users_client, "get_by_ids") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1056,8 +1392,8 @@ def test_follow_user_response_structure(self): ) - def test_unmute_user_request_structure(self): - """Test unmute_user request structure.""" + def test_get_following_request_structure(self): + """Test get_following request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1066,26 +1402,25 @@ def test_unmute_user_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["source_user_id"] = "test_value" - kwargs["target_user_id"] = "test_value" + kwargs["id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.users_client, "unmute_user") + method = getattr(self.users_client, "get_following") result = method(**kwargs) # Verify the request was made - mock_session.delete.assert_called_once() + mock_session.get.assert_called_once() # Verify request structure - call_args = mock_session.delete.call_args + call_args = mock_session.get.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{source_user_id}/muting/{target_user_id}" + expected_path = "/2/users/{id}/following" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1094,12 +1429,12 @@ def test_unmute_user_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for unmute_user: {e}") + pytest.fail(f"Contract test failed for get_following: {e}") - def test_unmute_user_required_parameters(self): - """Test that unmute_user handles parameters correctly.""" - method = getattr(self.users_client, "unmute_user") + def test_get_following_required_parameters(self): + """Test that get_following handles parameters correctly.""" + method = getattr(self.users_client, "get_following") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1107,14 +1442,14 @@ def test_unmute_user_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response + mock_session.get.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_unmute_user_response_structure(self): - """Test unmute_user response structure validation.""" + def test_get_following_response_structure(self): + """Test get_following response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1124,14 +1459,13 @@ def test_unmute_user_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["source_user_id"] = "test" - kwargs["target_user_id"] = "test" + kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "unmute_user") + method = getattr(self.users_client, "get_following") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1143,8 +1477,8 @@ def test_unmute_user_response_structure(self): ) - def test_unblock_users_dms_request_structure(self): - """Test unblock_users_dms request structure.""" + def test_follow_user_request_structure(self): + """Test follow_user request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1159,9 +1493,13 @@ def test_unblock_users_dms_request_structure(self): # Add required parameters kwargs["id"] = "test_value" # Add request body if required + # Import and create proper request model instance + from xdk.users.models import FollowUserRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = FollowUserRequest() # Call the method try: - method = getattr(self.users_client, "unblock_users_dms") + method = getattr(self.users_client, "follow_user") result = method(**kwargs) # Verify the request was made mock_session.post.assert_called_once() @@ -1171,7 +1509,7 @@ def test_unblock_users_dms_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/dm/unblock" + expected_path = "/2/users/{id}/following" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1180,12 +1518,12 @@ def test_unblock_users_dms_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for unblock_users_dms: {e}") + pytest.fail(f"Contract test failed for follow_user: {e}") - def test_unblock_users_dms_required_parameters(self): - """Test that unblock_users_dms handles parameters correctly.""" - method = getattr(self.users_client, "unblock_users_dms") + def test_follow_user_required_parameters(self): + """Test that follow_user handles parameters correctly.""" + method = getattr(self.users_client, "follow_user") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1199,8 +1537,8 @@ def test_unblock_users_dms_required_parameters(self): method() - def test_unblock_users_dms_response_structure(self): - """Test unblock_users_dms response structure validation.""" + def test_follow_user_response_structure(self): + """Test follow_user response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1215,8 +1553,12 @@ def test_unblock_users_dms_response_structure(self): kwargs = {} kwargs["id"] = "test" # Add request body if required + # Import and create proper request model instance + from xdk.users.models import FollowUserRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = FollowUserRequest() # Call method and verify response structure - method = getattr(self.users_client, "unblock_users_dms") + method = getattr(self.users_client, "follow_user") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1228,8 +1570,8 @@ def test_unblock_users_dms_response_structure(self): ) - def test_unfollow_user_request_structure(self): - """Test unfollow_user request structure.""" + def test_get_me_request_structure(self): + """Test get_me request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1238,26 +1580,24 @@ def test_unfollow_user_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["source_user_id"] = "test_value" - kwargs["target_user_id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.users_client, "unfollow_user") + method = getattr(self.users_client, "get_me") result = method(**kwargs) # Verify the request was made - mock_session.delete.assert_called_once() + mock_session.get.assert_called_once() # Verify request structure - call_args = mock_session.delete.call_args + call_args = mock_session.get.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{source_user_id}/following/{target_user_id}" + expected_path = "/2/users/me" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1266,27 +1606,27 @@ def test_unfollow_user_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for unfollow_user: {e}") + pytest.fail(f"Contract test failed for get_me: {e}") - def test_unfollow_user_required_parameters(self): - """Test that unfollow_user handles parameters correctly.""" - method = getattr(self.users_client, "unfollow_user") - # Test with missing required parameters - mock the request to avoid network calls + def test_get_me_required_parameters(self): + """Test that get_me handles parameters correctly.""" + method = getattr(self.users_client, "get_me") + # No required parameters, method should be callable without args with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): + mock_response.status_code = 200 + mock_response.json.return_value = {} + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + try: method() + except Exception as e: + pytest.fail(f"Method with no required params should be callable: {e}") - def test_unfollow_user_response_structure(self): - """Test unfollow_user response structure validation.""" + def test_get_me_response_structure(self): + """Test get_me response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1296,14 +1636,12 @@ def test_unfollow_user_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["source_user_id"] = "test" - kwargs["target_user_id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "unfollow_user") + method = getattr(self.users_client, "get_me") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1315,8 +1653,8 @@ def test_unfollow_user_response_structure(self): ) - def test_get_lists_members_request_structure(self): - """Test get_lists_members request structure.""" + def test_get_by_id_request_structure(self): + """Test get_by_id request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1333,7 +1671,7 @@ def test_get_lists_members_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_lists_members") + method = getattr(self.users_client, "get_by_id") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -1343,7 +1681,7 @@ def test_get_lists_members_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/lists/{id}/members" + expected_path = "/2/users/{id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1352,12 +1690,12 @@ def test_get_lists_members_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_lists_members: {e}") + pytest.fail(f"Contract test failed for get_by_id: {e}") - def test_get_lists_members_required_parameters(self): - """Test that get_lists_members handles parameters correctly.""" - method = getattr(self.users_client, "get_lists_members") + def test_get_by_id_required_parameters(self): + """Test that get_by_id handles parameters correctly.""" + method = getattr(self.users_client, "get_by_id") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1371,8 +1709,8 @@ def test_get_lists_members_required_parameters(self): method() - def test_get_lists_members_response_structure(self): - """Test get_lists_members response structure validation.""" + def test_get_by_id_response_structure(self): + """Test get_by_id response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1388,7 +1726,7 @@ def test_get_lists_members_response_structure(self): kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_lists_members") + method = getattr(self.users_client, "get_by_id") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1400,8 +1738,8 @@ def test_get_lists_members_response_structure(self): ) - def test_get_posts_reposted_by_request_structure(self): - """Test get_posts_reposted_by request structure.""" + def test_get_blocking_request_structure(self): + """Test get_blocking request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1418,7 +1756,7 @@ def test_get_posts_reposted_by_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_posts_reposted_by") + method = getattr(self.users_client, "get_blocking") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -1428,7 +1766,7 @@ def test_get_posts_reposted_by_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/tweets/{id}/retweeted_by" + expected_path = "/2/users/{id}/blocking" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1437,12 +1775,12 @@ def test_get_posts_reposted_by_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_posts_reposted_by: {e}") + pytest.fail(f"Contract test failed for get_blocking: {e}") - def test_get_posts_reposted_by_required_parameters(self): - """Test that get_posts_reposted_by handles parameters correctly.""" - method = getattr(self.users_client, "get_posts_reposted_by") + def test_get_blocking_required_parameters(self): + """Test that get_blocking handles parameters correctly.""" + method = getattr(self.users_client, "get_blocking") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1456,8 +1794,8 @@ def test_get_posts_reposted_by_required_parameters(self): method() - def test_get_posts_reposted_by_response_structure(self): - """Test get_posts_reposted_by response structure validation.""" + def test_get_blocking_response_structure(self): + """Test get_blocking response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1473,7 +1811,7 @@ def test_get_posts_reposted_by_response_structure(self): kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_posts_reposted_by") + method = getattr(self.users_client, "get_blocking") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1485,8 +1823,8 @@ def test_get_posts_reposted_by_response_structure(self): ) - def test_get_users_by_id_request_structure(self): - """Test get_users_by_id request structure.""" + def test_block_dms_request_structure(self): + """Test block_dms request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1495,7 +1833,7 @@ def test_get_users_by_id_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters @@ -1503,17 +1841,17 @@ def test_get_users_by_id_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_users_by_id") + method = getattr(self.users_client, "block_dms") result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.post.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.post.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}" + expected_path = "/2/users/{id}/dm/block" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1522,12 +1860,12 @@ def test_get_users_by_id_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_by_id: {e}") + pytest.fail(f"Contract test failed for block_dms: {e}") - def test_get_users_by_id_required_parameters(self): - """Test that get_users_by_id handles parameters correctly.""" - method = getattr(self.users_client, "get_users_by_id") + def test_block_dms_required_parameters(self): + """Test that block_dms handles parameters correctly.""" + method = getattr(self.users_client, "block_dms") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1535,14 +1873,14 @@ def test_get_users_by_id_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_get_users_by_id_response_structure(self): - """Test get_users_by_id response structure validation.""" + def test_block_dms_response_structure(self): + """Test block_dms response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1552,13 +1890,13 @@ def test_get_users_by_id_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare minimal valid parameters kwargs = {} kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_users_by_id") + method = getattr(self.users_client, "block_dms") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1570,8 +1908,8 @@ def test_get_users_by_id_response_structure(self): ) - def test_get_users_by_usernames_request_structure(self): - """Test get_users_by_usernames request structure.""" + def test_unfollow_user_request_structure(self): + """Test unfollow_user request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1580,25 +1918,26 @@ def test_get_users_by_usernames_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["usernames"] = ["test_item"] + kwargs["source_user_id"] = "test_value" + kwargs["target_user_id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_users_by_usernames") + method = getattr(self.users_client, "unfollow_user") result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.delete.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.delete.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/by" + expected_path = "/2/users/{source_user_id}/following/{target_user_id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1607,12 +1946,12 @@ def test_get_users_by_usernames_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_by_usernames: {e}") + pytest.fail(f"Contract test failed for unfollow_user: {e}") - def test_get_users_by_usernames_required_parameters(self): - """Test that get_users_by_usernames handles parameters correctly.""" - method = getattr(self.users_client, "get_users_by_usernames") + def test_unfollow_user_required_parameters(self): + """Test that unfollow_user handles parameters correctly.""" + method = getattr(self.users_client, "unfollow_user") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1620,14 +1959,14 @@ def test_get_users_by_usernames_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_get_users_by_usernames_response_structure(self): - """Test get_users_by_usernames response structure validation.""" + def test_unfollow_user_response_structure(self): + """Test unfollow_user response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1637,13 +1976,14 @@ def test_get_users_by_usernames_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["usernames"] = ["test"] + kwargs["source_user_id"] = "test" + kwargs["target_user_id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_users_by_usernames") + method = getattr(self.users_client, "unfollow_user") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1655,8 +1995,8 @@ def test_get_users_by_usernames_response_structure(self): ) - def test_get_posts_liking_users_request_structure(self): - """Test get_posts_liking_users request structure.""" + def test_get_followers_request_structure(self): + """Test get_followers request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1673,7 +2013,7 @@ def test_get_posts_liking_users_request_structure(self): # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_posts_liking_users") + method = getattr(self.users_client, "get_followers") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -1683,7 +2023,7 @@ def test_get_posts_liking_users_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/tweets/{id}/liking_users" + expected_path = "/2/users/{id}/followers" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1692,12 +2032,12 @@ def test_get_posts_liking_users_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_posts_liking_users: {e}") + pytest.fail(f"Contract test failed for get_followers: {e}") - def test_get_posts_liking_users_required_parameters(self): - """Test that get_posts_liking_users handles parameters correctly.""" - method = getattr(self.users_client, "get_posts_liking_users") + def test_get_followers_required_parameters(self): + """Test that get_followers handles parameters correctly.""" + method = getattr(self.users_client, "get_followers") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1711,8 +2051,8 @@ def test_get_posts_liking_users_required_parameters(self): method() - def test_get_posts_liking_users_response_structure(self): - """Test get_posts_liking_users response structure validation.""" + def test_get_followers_response_structure(self): + """Test get_followers response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1728,7 +2068,7 @@ def test_get_posts_liking_users_response_structure(self): kwargs["id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_posts_liking_users") + method = getattr(self.users_client, "get_followers") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -1740,8 +2080,8 @@ def test_get_posts_liking_users_response_structure(self): ) - def test_get_users_followers_request_structure(self): - """Test get_users_followers request structure.""" + def test_get_by_username_request_structure(self): + """Test get_by_username request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -1754,11 +2094,11 @@ def test_get_users_followers_request_structure(self): # Prepare test parameters kwargs = {} # Add required parameters - kwargs["id"] = "test_value" + kwargs["username"] = "test_username" # Add request body if required # Call the method try: - method = getattr(self.users_client, "get_users_followers") + method = getattr(self.users_client, "get_by_username") result = method(**kwargs) # Verify the request was made mock_session.get.assert_called_once() @@ -1768,7 +2108,7 @@ def test_get_users_followers_request_structure(self): called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/users/{id}/followers" + expected_path = "/2/users/by/username/{username}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -1777,12 +2117,12 @@ def test_get_users_followers_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_users_followers: {e}") + pytest.fail(f"Contract test failed for get_by_username: {e}") - def test_get_users_followers_required_parameters(self): - """Test that get_users_followers handles parameters correctly.""" - method = getattr(self.users_client, "get_users_followers") + def test_get_by_username_required_parameters(self): + """Test that get_by_username handles parameters correctly.""" + method = getattr(self.users_client, "get_by_username") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -1796,8 +2136,8 @@ def test_get_users_followers_required_parameters(self): method() - def test_get_users_followers_response_structure(self): - """Test get_users_followers response structure validation.""" + def test_get_by_username_response_structure(self): + """Test get_by_username response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -1810,10 +2150,10 @@ def test_get_users_followers_response_structure(self): mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["id"] = "test" + kwargs["username"] = "test_value" # Add request body if required # Call method and verify response structure - method = getattr(self.users_client, "get_users_followers") + method = getattr(self.users_client, "get_by_username") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed diff --git a/xdk/python/tests/users/test_generic.py b/xdk/python/tests/users/test_generic.py index b3154535..07d59920 100644 --- a/xdk/python/tests/users/test_generic.py +++ b/xdk/python/tests/users/test_generic.py @@ -1,5 +1,5 @@ """ -Auto-generated generic tests for Users client. +Auto-generated generic tests for {"class_name": "Users", "display_name": "users", "import_name": "users", "original": ["users"], "property_name": "users"} client. This module contains general tests that validate the overall client functionality, imports, and error handling that don't need to be diff --git a/xdk/python/tests/users/test_pagination.py b/xdk/python/tests/users/test_pagination.py index 9965384c..d2c96c3a 100644 --- a/xdk/python/tests/users/test_pagination.py +++ b/xdk/python/tests/users/test_pagination.py @@ -1,5 +1,5 @@ """ -Auto-generated pagination tests for Users client. +Auto-generated pagination tests for {"class_name": "Users", "display_name": "users", "import_name": "users", "original": ["users"], "property_name": "users"} client. This module contains tests that validate pagination functionality using the Cursor class for methods that support pagination. @@ -23,20 +23,20 @@ def setup_class(self): self.users_client = getattr(self.client, "users") - def test_get_lists_followers_cursor_creation(self): - """Test that get_lists_followers can be used with Cursor.""" - method = getattr(self.users_client, "get_lists_followers") + def test_get_followed_lists_cursor_creation(self): + """Test that get_followed_lists can be used with Cursor.""" + method = getattr(self.users_client, "get_followed_lists") # Should be able to create cursor without error try: test_cursor = cursor(method, "test_id", max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method getListsFollowers should support pagination") + pytest.fail(f"Method get_followed_lists should support pagination") - def test_get_lists_followers_cursor_pages(self): - """Test pagination with pages() for get_lists_followers.""" + def test_get_followed_lists_cursor_pages(self): + """Test pagination with pages() for get_followed_lists.""" with patch.object(self.client, "session") as mock_session: # Mock first page response first_page_response = Mock() @@ -57,7 +57,7 @@ def test_get_lists_followers_cursor_pages(self): # Return different responses for consecutive calls mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.users_client, "get_lists_followers") + method = getattr(self.users_client, "get_followed_lists") test_cursor = cursor(method, "test_id", max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" @@ -73,8 +73,8 @@ def test_get_lists_followers_cursor_pages(self): assert len(second_data) == 1, "Second page should have 1 item" - def test_get_lists_followers_cursor_items(self): - """Test pagination with items() for get_lists_followers.""" + def test_get_followed_lists_cursor_items(self): + """Test pagination with items() for get_followed_lists.""" with patch.object(self.client, "session") as mock_session: # Mock response with paginated data mock_response = Mock() @@ -93,7 +93,7 @@ def test_get_lists_followers_cursor_items(self): mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.users_client, "get_lists_followers") + method = getattr(self.users_client, "get_followed_lists") test_cursor = cursor(method, "test_id", max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items assert len(items) == 3, f"Should get 3 items, got {len(items)}" @@ -104,15 +104,15 @@ def test_get_lists_followers_cursor_items(self): ), "Items should have 'id' field" - def test_get_lists_followers_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_lists_followers.""" + def test_get_followed_lists_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_followed_lists.""" with patch.object(self.client, "session") as mock_session: mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.users_client, "get_lists_followers") + method = getattr(self.users_client, "get_followed_lists") # Test with max_results parameter test_cursor = cursor(method, "test_id", max_results=5) list(test_cursor.pages(1)) # Trigger one request @@ -165,20 +165,20 @@ def test_get_lists_followers_pagination_parameters(self): ), "Pagination token should be passed correctly" - def test_get_users_muting_cursor_creation(self): - """Test that get_users_muting can be used with Cursor.""" - method = getattr(self.users_client, "get_users_muting") + def test_get_list_memberships_cursor_creation(self): + """Test that get_list_memberships can be used with Cursor.""" + method = getattr(self.users_client, "get_list_memberships") # Should be able to create cursor without error try: test_cursor = cursor(method, "test_id", max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method getUsersMuting should support pagination") + pytest.fail(f"Method get_list_memberships should support pagination") - def test_get_users_muting_cursor_pages(self): - """Test pagination with pages() for get_users_muting.""" + def test_get_list_memberships_cursor_pages(self): + """Test pagination with pages() for get_list_memberships.""" with patch.object(self.client, "session") as mock_session: # Mock first page response first_page_response = Mock() @@ -199,7 +199,7 @@ def test_get_users_muting_cursor_pages(self): # Return different responses for consecutive calls mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.users_client, "get_users_muting") + method = getattr(self.users_client, "get_list_memberships") test_cursor = cursor(method, "test_id", max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" @@ -215,8 +215,8 @@ def test_get_users_muting_cursor_pages(self): assert len(second_data) == 1, "Second page should have 1 item" - def test_get_users_muting_cursor_items(self): - """Test pagination with items() for get_users_muting.""" + def test_get_list_memberships_cursor_items(self): + """Test pagination with items() for get_list_memberships.""" with patch.object(self.client, "session") as mock_session: # Mock response with paginated data mock_response = Mock() @@ -235,7 +235,7 @@ def test_get_users_muting_cursor_items(self): mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.users_client, "get_users_muting") + method = getattr(self.users_client, "get_list_memberships") test_cursor = cursor(method, "test_id", max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items assert len(items) == 3, f"Should get 3 items, got {len(items)}" @@ -246,15 +246,15 @@ def test_get_users_muting_cursor_items(self): ), "Items should have 'id' field" - def test_get_users_muting_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_muting.""" + def test_get_list_memberships_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_list_memberships.""" with patch.object(self.client, "session") as mock_session: mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.users_client, "get_users_muting") + method = getattr(self.users_client, "get_list_memberships") # Test with max_results parameter test_cursor = cursor(method, "test_id", max_results=5) list(test_cursor.pages(1)) # Trigger one request @@ -307,20 +307,20 @@ def test_get_users_muting_pagination_parameters(self): ), "Pagination token should be passed correctly" - def test_get_users_reposts_of_me_cursor_creation(self): - """Test that get_users_reposts_of_me can be used with Cursor.""" - method = getattr(self.users_client, "get_users_reposts_of_me") + def test_get_reposts_of_me_cursor_creation(self): + """Test that get_reposts_of_me can be used with Cursor.""" + method = getattr(self.users_client, "get_reposts_of_me") # Should be able to create cursor without error try: test_cursor = cursor(method, max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method getUsersRepostsOfMe should support pagination") + pytest.fail(f"Method get_reposts_of_me should support pagination") - def test_get_users_reposts_of_me_cursor_pages(self): - """Test pagination with pages() for get_users_reposts_of_me.""" + def test_get_reposts_of_me_cursor_pages(self): + """Test pagination with pages() for get_reposts_of_me.""" with patch.object(self.client, "session") as mock_session: # Mock first page response first_page_response = Mock() @@ -341,7 +341,7 @@ def test_get_users_reposts_of_me_cursor_pages(self): # Return different responses for consecutive calls mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.users_client, "get_users_reposts_of_me") + method = getattr(self.users_client, "get_reposts_of_me") test_cursor = cursor(method, max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" @@ -357,8 +357,8 @@ def test_get_users_reposts_of_me_cursor_pages(self): assert len(second_data) == 1, "Second page should have 1 item" - def test_get_users_reposts_of_me_cursor_items(self): - """Test pagination with items() for get_users_reposts_of_me.""" + def test_get_reposts_of_me_cursor_items(self): + """Test pagination with items() for get_reposts_of_me.""" with patch.object(self.client, "session") as mock_session: # Mock response with paginated data mock_response = Mock() @@ -377,7 +377,7 @@ def test_get_users_reposts_of_me_cursor_items(self): mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.users_client, "get_users_reposts_of_me") + method = getattr(self.users_client, "get_reposts_of_me") test_cursor = cursor(method, max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items assert len(items) == 3, f"Should get 3 items, got {len(items)}" @@ -388,15 +388,15 @@ def test_get_users_reposts_of_me_cursor_items(self): ), "Items should have 'id' field" - def test_get_users_reposts_of_me_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_reposts_of_me.""" + def test_get_reposts_of_me_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_reposts_of_me.""" with patch.object(self.client, "session") as mock_session: mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.users_client, "get_users_reposts_of_me") + method = getattr(self.users_client, "get_reposts_of_me") # Test with max_results parameter test_cursor = cursor(method, max_results=5) list(test_cursor.pages(1)) # Trigger one request @@ -449,20 +449,446 @@ def test_get_users_reposts_of_me_pagination_parameters(self): ), "Pagination token should be passed correctly" - def test_search_users_cursor_creation(self): - """Test that search_users can be used with Cursor.""" - method = getattr(self.users_client, "search_users") + def test_get_owned_lists_cursor_creation(self): + """Test that get_owned_lists can be used with Cursor.""" + method = getattr(self.users_client, "get_owned_lists") # Should be able to create cursor without error try: - test_cursor = cursor(method, "test_query", max_results=10) + test_cursor = cursor(method, "test_id", max_results=10) + assert test_cursor is not None + assert isinstance(test_cursor, Cursor) + except PaginationError: + pytest.fail(f"Method get_owned_lists should support pagination") + + + def test_get_owned_lists_cursor_pages(self): + """Test pagination with pages() for get_owned_lists.""" + with patch.object(self.client, "session") as mock_session: + # Mock first page response + first_page_response = Mock() + first_page_response.status_code = 200 + first_page_response.json.return_value = { + "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], + "meta": {"next_token": "next_page_token", "result_count": 2}, + } + first_page_response.raise_for_status.return_value = None + # Mock second page response (no next token = end of pagination) + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [{"id": "3", "name": "Item 3"}], + "meta": {"result_count": 1}, + } + second_page_response.raise_for_status.return_value = None + # Return different responses for consecutive calls + mock_session.get.side_effect = [first_page_response, second_page_response] + # Test pagination + method = getattr(self.users_client, "get_owned_lists") + test_cursor = cursor(method, "test_id", max_results=2) + pages = list(test_cursor.pages(2)) # Limit to 2 pages + assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" + # Verify first page + first_page = pages[0] + assert hasattr(first_page, "data") + first_data = getattr(first_page, "data") + assert len(first_data) == 2, "First page should have 2 items" + # Verify second page + second_page = pages[1] + assert hasattr(second_page, "data") + second_data = getattr(second_page, "data") + assert len(second_data) == 1, "Second page should have 1 item" + + + def test_get_owned_lists_cursor_items(self): + """Test pagination with items() for get_owned_lists.""" + with patch.object(self.client, "session") as mock_session: + # Mock response with paginated data + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "data": [ + {"id": "1", "name": "Item 1"}, + {"id": "2", "name": "Item 2"}, + {"id": "3", "name": "Item 3"}, + ], + "meta": { + "result_count": 3 + # No next_token = single page + }, + } + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + # Test item iteration + method = getattr(self.users_client, "get_owned_lists") + test_cursor = cursor(method, "test_id", max_results=10) + items = list(test_cursor.items(5)) # Limit to 5 items + assert len(items) == 3, f"Should get 3 items, got {len(items)}" + # Verify items have expected structure + for item in items: + assert "id" in item or hasattr( + item, "id" + ), "Items should have 'id' field" + + + def test_get_owned_lists_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_owned_lists.""" + with patch.object(self.client, "session") as mock_session: + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + method = getattr(self.users_client, "get_owned_lists") + # Test with max_results parameter + test_cursor = cursor(method, "test_id", max_results=5) + list(test_cursor.pages(1)) # Trigger one request + # Verify max_results was passed in request + call_args = mock_session.get.call_args + if call_args and "params" in call_args[1]: + params = call_args[1]["params"] + assert ( + "max_results" in params + ), "max_results should be in request parameters" + # Test with pagination token (simulate second page request) + mock_session.reset_mock() + mock_response_with_token = Mock() + mock_response_with_token.status_code = 200 + mock_response_with_token.json.return_value = { + "data": [{"id": "1"}], + "meta": {"next_token": "next_token_value", "result_count": 1}, + } + mock_response_with_token.raise_for_status.return_value = None + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [], + "meta": {"result_count": 0}, + } + second_page_response.raise_for_status.return_value = None + mock_session.get.side_effect = [ + mock_response_with_token, + second_page_response, + ] + test_cursor = cursor(method, "test_id", max_results=1) + pages = list(test_cursor.pages(2)) + # Should have made 2 requests + assert ( + mock_session.get.call_count == 2 + ), "Should make 2 requests for 2 pages" + # Second request should include pagination token + second_call_args = mock_session.get.call_args_list[1] + if ( + second_call_args + and len(second_call_args) > 1 + and "params" in second_call_args[1] + ): + second_params = second_call_args[1]["params"] + assert ( + "pagination_token" in second_params + ), "Second request should include pagination_token" + assert ( + second_params["pagination_token"] == "next_token_value" + ), "Pagination token should be passed correctly" + + + def test_get_posts_cursor_creation(self): + """Test that get_posts can be used with Cursor.""" + method = getattr(self.users_client, "get_posts") + # Should be able to create cursor without error + try: + test_cursor = cursor(method, "test_id", max_results=10) + assert test_cursor is not None + assert isinstance(test_cursor, Cursor) + except PaginationError: + pytest.fail(f"Method get_posts should support pagination") + + + def test_get_posts_cursor_pages(self): + """Test pagination with pages() for get_posts.""" + with patch.object(self.client, "session") as mock_session: + # Mock first page response + first_page_response = Mock() + first_page_response.status_code = 200 + first_page_response.json.return_value = { + "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], + "meta": {"next_token": "next_page_token", "result_count": 2}, + } + first_page_response.raise_for_status.return_value = None + # Mock second page response (no next token = end of pagination) + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [{"id": "3", "name": "Item 3"}], + "meta": {"result_count": 1}, + } + second_page_response.raise_for_status.return_value = None + # Return different responses for consecutive calls + mock_session.get.side_effect = [first_page_response, second_page_response] + # Test pagination + method = getattr(self.users_client, "get_posts") + test_cursor = cursor(method, "test_id", max_results=2) + pages = list(test_cursor.pages(2)) # Limit to 2 pages + assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" + # Verify first page + first_page = pages[0] + assert hasattr(first_page, "data") + first_data = getattr(first_page, "data") + assert len(first_data) == 2, "First page should have 2 items" + # Verify second page + second_page = pages[1] + assert hasattr(second_page, "data") + second_data = getattr(second_page, "data") + assert len(second_data) == 1, "Second page should have 1 item" + + + def test_get_posts_cursor_items(self): + """Test pagination with items() for get_posts.""" + with patch.object(self.client, "session") as mock_session: + # Mock response with paginated data + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "data": [ + {"id": "1", "name": "Item 1"}, + {"id": "2", "name": "Item 2"}, + {"id": "3", "name": "Item 3"}, + ], + "meta": { + "result_count": 3 + # No next_token = single page + }, + } + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + # Test item iteration + method = getattr(self.users_client, "get_posts") + test_cursor = cursor(method, "test_id", max_results=10) + items = list(test_cursor.items(5)) # Limit to 5 items + assert len(items) == 3, f"Should get 3 items, got {len(items)}" + # Verify items have expected structure + for item in items: + assert "id" in item or hasattr( + item, "id" + ), "Items should have 'id' field" + + + def test_get_posts_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_posts.""" + with patch.object(self.client, "session") as mock_session: + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + method = getattr(self.users_client, "get_posts") + # Test with max_results parameter + test_cursor = cursor(method, "test_id", max_results=5) + list(test_cursor.pages(1)) # Trigger one request + # Verify max_results was passed in request + call_args = mock_session.get.call_args + if call_args and "params" in call_args[1]: + params = call_args[1]["params"] + assert ( + "max_results" in params + ), "max_results should be in request parameters" + # Test with pagination token (simulate second page request) + mock_session.reset_mock() + mock_response_with_token = Mock() + mock_response_with_token.status_code = 200 + mock_response_with_token.json.return_value = { + "data": [{"id": "1"}], + "meta": {"next_token": "next_token_value", "result_count": 1}, + } + mock_response_with_token.raise_for_status.return_value = None + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [], + "meta": {"result_count": 0}, + } + second_page_response.raise_for_status.return_value = None + mock_session.get.side_effect = [ + mock_response_with_token, + second_page_response, + ] + test_cursor = cursor(method, "test_id", max_results=1) + pages = list(test_cursor.pages(2)) + # Should have made 2 requests + assert ( + mock_session.get.call_count == 2 + ), "Should make 2 requests for 2 pages" + # Second request should include pagination token + second_call_args = mock_session.get.call_args_list[1] + if ( + second_call_args + and len(second_call_args) > 1 + and "params" in second_call_args[1] + ): + second_params = second_call_args[1]["params"] + assert ( + "pagination_token" in second_params + ), "Second request should include pagination_token" + assert ( + second_params["pagination_token"] == "next_token_value" + ), "Pagination token should be passed correctly" + + + def test_get_liked_posts_cursor_creation(self): + """Test that get_liked_posts can be used with Cursor.""" + method = getattr(self.users_client, "get_liked_posts") + # Should be able to create cursor without error + try: + test_cursor = cursor(method, "test_id", max_results=10) + assert test_cursor is not None + assert isinstance(test_cursor, Cursor) + except PaginationError: + pytest.fail(f"Method get_liked_posts should support pagination") + + + def test_get_liked_posts_cursor_pages(self): + """Test pagination with pages() for get_liked_posts.""" + with patch.object(self.client, "session") as mock_session: + # Mock first page response + first_page_response = Mock() + first_page_response.status_code = 200 + first_page_response.json.return_value = { + "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], + "meta": {"next_token": "next_page_token", "result_count": 2}, + } + first_page_response.raise_for_status.return_value = None + # Mock second page response (no next token = end of pagination) + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [{"id": "3", "name": "Item 3"}], + "meta": {"result_count": 1}, + } + second_page_response.raise_for_status.return_value = None + # Return different responses for consecutive calls + mock_session.get.side_effect = [first_page_response, second_page_response] + # Test pagination + method = getattr(self.users_client, "get_liked_posts") + test_cursor = cursor(method, "test_id", max_results=2) + pages = list(test_cursor.pages(2)) # Limit to 2 pages + assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" + # Verify first page + first_page = pages[0] + assert hasattr(first_page, "data") + first_data = getattr(first_page, "data") + assert len(first_data) == 2, "First page should have 2 items" + # Verify second page + second_page = pages[1] + assert hasattr(second_page, "data") + second_data = getattr(second_page, "data") + assert len(second_data) == 1, "Second page should have 1 item" + + + def test_get_liked_posts_cursor_items(self): + """Test pagination with items() for get_liked_posts.""" + with patch.object(self.client, "session") as mock_session: + # Mock response with paginated data + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "data": [ + {"id": "1", "name": "Item 1"}, + {"id": "2", "name": "Item 2"}, + {"id": "3", "name": "Item 3"}, + ], + "meta": { + "result_count": 3 + # No next_token = single page + }, + } + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + # Test item iteration + method = getattr(self.users_client, "get_liked_posts") + test_cursor = cursor(method, "test_id", max_results=10) + items = list(test_cursor.items(5)) # Limit to 5 items + assert len(items) == 3, f"Should get 3 items, got {len(items)}" + # Verify items have expected structure + for item in items: + assert "id" in item or hasattr( + item, "id" + ), "Items should have 'id' field" + + + def test_get_liked_posts_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_liked_posts.""" + with patch.object(self.client, "session") as mock_session: + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + method = getattr(self.users_client, "get_liked_posts") + # Test with max_results parameter + test_cursor = cursor(method, "test_id", max_results=5) + list(test_cursor.pages(1)) # Trigger one request + # Verify max_results was passed in request + call_args = mock_session.get.call_args + if call_args and "params" in call_args[1]: + params = call_args[1]["params"] + assert ( + "max_results" in params + ), "max_results should be in request parameters" + # Test with pagination token (simulate second page request) + mock_session.reset_mock() + mock_response_with_token = Mock() + mock_response_with_token.status_code = 200 + mock_response_with_token.json.return_value = { + "data": [{"id": "1"}], + "meta": {"next_token": "next_token_value", "result_count": 1}, + } + mock_response_with_token.raise_for_status.return_value = None + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [], + "meta": {"result_count": 0}, + } + second_page_response.raise_for_status.return_value = None + mock_session.get.side_effect = [ + mock_response_with_token, + second_page_response, + ] + test_cursor = cursor(method, "test_id", max_results=1) + pages = list(test_cursor.pages(2)) + # Should have made 2 requests + assert ( + mock_session.get.call_count == 2 + ), "Should make 2 requests for 2 pages" + # Second request should include pagination token + second_call_args = mock_session.get.call_args_list[1] + if ( + second_call_args + and len(second_call_args) > 1 + and "params" in second_call_args[1] + ): + second_params = second_call_args[1]["params"] + assert ( + "pagination_token" in second_params + ), "Second request should include pagination_token" + assert ( + second_params["pagination_token"] == "next_token_value" + ), "Pagination token should be passed correctly" + + + def test_get_timeline_cursor_creation(self): + """Test that get_timeline can be used with Cursor.""" + method = getattr(self.users_client, "get_timeline") + # Should be able to create cursor without error + try: + test_cursor = cursor(method, "test_id", max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method searchUsers should support pagination") + pytest.fail(f"Method get_timeline should support pagination") - def test_search_users_cursor_pages(self): - """Test pagination with pages() for search_users.""" + def test_get_timeline_cursor_pages(self): + """Test pagination with pages() for get_timeline.""" with patch.object(self.client, "session") as mock_session: # Mock first page response first_page_response = Mock() @@ -483,8 +909,8 @@ def test_search_users_cursor_pages(self): # Return different responses for consecutive calls mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.users_client, "search_users") - test_cursor = cursor(method, "test_query", max_results=2) + method = getattr(self.users_client, "get_timeline") + test_cursor = cursor(method, "test_id", max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" # Verify first page @@ -499,8 +925,8 @@ def test_search_users_cursor_pages(self): assert len(second_data) == 1, "Second page should have 1 item" - def test_search_users_cursor_items(self): - """Test pagination with items() for search_users.""" + def test_get_timeline_cursor_items(self): + """Test pagination with items() for get_timeline.""" with patch.object(self.client, "session") as mock_session: # Mock response with paginated data mock_response = Mock() @@ -519,8 +945,8 @@ def test_search_users_cursor_items(self): mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.users_client, "search_users") - test_cursor = cursor(method, "test_query", max_results=10) + method = getattr(self.users_client, "get_timeline") + test_cursor = cursor(method, "test_id", max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items assert len(items) == 3, f"Should get 3 items, got {len(items)}" # Verify items have expected structure @@ -530,17 +956,17 @@ def test_search_users_cursor_items(self): ), "Items should have 'id' field" - def test_search_users_pagination_parameters(self): - """Test that pagination parameters are handled correctly for search_users.""" + def test_get_timeline_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_timeline.""" with patch.object(self.client, "session") as mock_session: mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.users_client, "search_users") + method = getattr(self.users_client, "get_timeline") # Test with max_results parameter - test_cursor = cursor(method, "test_query", max_results=5) + test_cursor = cursor(method, "test_id", max_results=5) list(test_cursor.pages(1)) # Trigger one request # Verify max_results was passed in request call_args = mock_session.get.call_args @@ -569,7 +995,7 @@ def test_search_users_pagination_parameters(self): mock_response_with_token, second_page_response, ] - test_cursor = cursor(method, "test_query", max_results=1) + test_cursor = cursor(method, "test_id", max_results=1) pages = list(test_cursor.pages(2)) # Should have made 2 requests assert ( @@ -584,27 +1010,27 @@ def test_search_users_pagination_parameters(self): ): second_params = second_call_args[1]["params"] assert ( - "next_token" in second_params - ), "Second request should include next_token" + "pagination_token" in second_params + ), "Second request should include pagination_token" assert ( - second_params["next_token"] == "next_token_value" + second_params["pagination_token"] == "next_token_value" ), "Pagination token should be passed correctly" - def test_get_users_blocking_cursor_creation(self): - """Test that get_users_blocking can be used with Cursor.""" - method = getattr(self.users_client, "get_users_blocking") + def test_get_mentions_cursor_creation(self): + """Test that get_mentions can be used with Cursor.""" + method = getattr(self.users_client, "get_mentions") # Should be able to create cursor without error try: test_cursor = cursor(method, "test_id", max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method getUsersBlocking should support pagination") + pytest.fail(f"Method get_mentions should support pagination") - def test_get_users_blocking_cursor_pages(self): - """Test pagination with pages() for get_users_blocking.""" + def test_get_mentions_cursor_pages(self): + """Test pagination with pages() for get_mentions.""" with patch.object(self.client, "session") as mock_session: # Mock first page response first_page_response = Mock() @@ -625,7 +1051,7 @@ def test_get_users_blocking_cursor_pages(self): # Return different responses for consecutive calls mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.users_client, "get_users_blocking") + method = getattr(self.users_client, "get_mentions") test_cursor = cursor(method, "test_id", max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" @@ -641,8 +1067,8 @@ def test_get_users_blocking_cursor_pages(self): assert len(second_data) == 1, "Second page should have 1 item" - def test_get_users_blocking_cursor_items(self): - """Test pagination with items() for get_users_blocking.""" + def test_get_mentions_cursor_items(self): + """Test pagination with items() for get_mentions.""" with patch.object(self.client, "session") as mock_session: # Mock response with paginated data mock_response = Mock() @@ -661,7 +1087,7 @@ def test_get_users_blocking_cursor_items(self): mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.users_client, "get_users_blocking") + method = getattr(self.users_client, "get_mentions") test_cursor = cursor(method, "test_id", max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items assert len(items) == 3, f"Should get 3 items, got {len(items)}" @@ -672,15 +1098,15 @@ def test_get_users_blocking_cursor_items(self): ), "Items should have 'id' field" - def test_get_users_blocking_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_blocking.""" + def test_get_mentions_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_mentions.""" with patch.object(self.client, "session") as mock_session: mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.users_client, "get_users_blocking") + method = getattr(self.users_client, "get_mentions") # Test with max_results parameter test_cursor = cursor(method, "test_id", max_results=5) list(test_cursor.pages(1)) # Trigger one request @@ -733,20 +1159,162 @@ def test_get_users_blocking_pagination_parameters(self): ), "Pagination token should be passed correctly" - def test_get_users_following_cursor_creation(self): - """Test that get_users_following can be used with Cursor.""" - method = getattr(self.users_client, "get_users_following") + def test_search_cursor_creation(self): + """Test that search can be used with Cursor.""" + method = getattr(self.users_client, "search") + # Should be able to create cursor without error + try: + test_cursor = cursor(method, "test_query", max_results=10) + assert test_cursor is not None + assert isinstance(test_cursor, Cursor) + except PaginationError: + pytest.fail(f"Method search should support pagination") + + + def test_search_cursor_pages(self): + """Test pagination with pages() for search.""" + with patch.object(self.client, "session") as mock_session: + # Mock first page response + first_page_response = Mock() + first_page_response.status_code = 200 + first_page_response.json.return_value = { + "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], + "meta": {"next_token": "next_page_token", "result_count": 2}, + } + first_page_response.raise_for_status.return_value = None + # Mock second page response (no next token = end of pagination) + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [{"id": "3", "name": "Item 3"}], + "meta": {"result_count": 1}, + } + second_page_response.raise_for_status.return_value = None + # Return different responses for consecutive calls + mock_session.get.side_effect = [first_page_response, second_page_response] + # Test pagination + method = getattr(self.users_client, "search") + test_cursor = cursor(method, "test_query", max_results=2) + pages = list(test_cursor.pages(2)) # Limit to 2 pages + assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" + # Verify first page + first_page = pages[0] + assert hasattr(first_page, "data") + first_data = getattr(first_page, "data") + assert len(first_data) == 2, "First page should have 2 items" + # Verify second page + second_page = pages[1] + assert hasattr(second_page, "data") + second_data = getattr(second_page, "data") + assert len(second_data) == 1, "Second page should have 1 item" + + + def test_search_cursor_items(self): + """Test pagination with items() for search.""" + with patch.object(self.client, "session") as mock_session: + # Mock response with paginated data + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "data": [ + {"id": "1", "name": "Item 1"}, + {"id": "2", "name": "Item 2"}, + {"id": "3", "name": "Item 3"}, + ], + "meta": { + "result_count": 3 + # No next_token = single page + }, + } + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + # Test item iteration + method = getattr(self.users_client, "search") + test_cursor = cursor(method, "test_query", max_results=10) + items = list(test_cursor.items(5)) # Limit to 5 items + assert len(items) == 3, f"Should get 3 items, got {len(items)}" + # Verify items have expected structure + for item in items: + assert "id" in item or hasattr( + item, "id" + ), "Items should have 'id' field" + + + def test_search_pagination_parameters(self): + """Test that pagination parameters are handled correctly for search.""" + with patch.object(self.client, "session") as mock_session: + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + method = getattr(self.users_client, "search") + # Test with max_results parameter + test_cursor = cursor(method, "test_query", max_results=5) + list(test_cursor.pages(1)) # Trigger one request + # Verify max_results was passed in request + call_args = mock_session.get.call_args + if call_args and "params" in call_args[1]: + params = call_args[1]["params"] + assert ( + "max_results" in params + ), "max_results should be in request parameters" + # Test with pagination token (simulate second page request) + mock_session.reset_mock() + mock_response_with_token = Mock() + mock_response_with_token.status_code = 200 + mock_response_with_token.json.return_value = { + "data": [{"id": "1"}], + "meta": {"next_token": "next_token_value", "result_count": 1}, + } + mock_response_with_token.raise_for_status.return_value = None + second_page_response = Mock() + second_page_response.status_code = 200 + second_page_response.json.return_value = { + "data": [], + "meta": {"result_count": 0}, + } + second_page_response.raise_for_status.return_value = None + mock_session.get.side_effect = [ + mock_response_with_token, + second_page_response, + ] + test_cursor = cursor(method, "test_query", max_results=1) + pages = list(test_cursor.pages(2)) + # Should have made 2 requests + assert ( + mock_session.get.call_count == 2 + ), "Should make 2 requests for 2 pages" + # Second request should include pagination token + second_call_args = mock_session.get.call_args_list[1] + if ( + second_call_args + and len(second_call_args) > 1 + and "params" in second_call_args[1] + ): + second_params = second_call_args[1]["params"] + assert ( + "next_token" in second_params + ), "Second request should include next_token" + assert ( + second_params["next_token"] == "next_token_value" + ), "Pagination token should be passed correctly" + + + def test_get_muting_cursor_creation(self): + """Test that get_muting can be used with Cursor.""" + method = getattr(self.users_client, "get_muting") # Should be able to create cursor without error try: test_cursor = cursor(method, "test_id", max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method getUsersFollowing should support pagination") + pytest.fail(f"Method get_muting should support pagination") - def test_get_users_following_cursor_pages(self): - """Test pagination with pages() for get_users_following.""" + def test_get_muting_cursor_pages(self): + """Test pagination with pages() for get_muting.""" with patch.object(self.client, "session") as mock_session: # Mock first page response first_page_response = Mock() @@ -767,7 +1335,7 @@ def test_get_users_following_cursor_pages(self): # Return different responses for consecutive calls mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.users_client, "get_users_following") + method = getattr(self.users_client, "get_muting") test_cursor = cursor(method, "test_id", max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" @@ -783,8 +1351,8 @@ def test_get_users_following_cursor_pages(self): assert len(second_data) == 1, "Second page should have 1 item" - def test_get_users_following_cursor_items(self): - """Test pagination with items() for get_users_following.""" + def test_get_muting_cursor_items(self): + """Test pagination with items() for get_muting.""" with patch.object(self.client, "session") as mock_session: # Mock response with paginated data mock_response = Mock() @@ -803,7 +1371,7 @@ def test_get_users_following_cursor_items(self): mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.users_client, "get_users_following") + method = getattr(self.users_client, "get_muting") test_cursor = cursor(method, "test_id", max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items assert len(items) == 3, f"Should get 3 items, got {len(items)}" @@ -814,15 +1382,15 @@ def test_get_users_following_cursor_items(self): ), "Items should have 'id' field" - def test_get_users_following_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_following.""" + def test_get_muting_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_muting.""" with patch.object(self.client, "session") as mock_session: mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.users_client, "get_users_following") + method = getattr(self.users_client, "get_muting") # Test with max_results parameter test_cursor = cursor(method, "test_id", max_results=5) list(test_cursor.pages(1)) # Trigger one request @@ -875,20 +1443,20 @@ def test_get_users_following_pagination_parameters(self): ), "Pagination token should be passed correctly" - def test_get_lists_members_cursor_creation(self): - """Test that get_lists_members can be used with Cursor.""" - method = getattr(self.users_client, "get_lists_members") + def test_get_bookmarks_cursor_creation(self): + """Test that get_bookmarks can be used with Cursor.""" + method = getattr(self.users_client, "get_bookmarks") # Should be able to create cursor without error try: test_cursor = cursor(method, "test_id", max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method getListsMembers should support pagination") + pytest.fail(f"Method get_bookmarks should support pagination") - def test_get_lists_members_cursor_pages(self): - """Test pagination with pages() for get_lists_members.""" + def test_get_bookmarks_cursor_pages(self): + """Test pagination with pages() for get_bookmarks.""" with patch.object(self.client, "session") as mock_session: # Mock first page response first_page_response = Mock() @@ -909,7 +1477,7 @@ def test_get_lists_members_cursor_pages(self): # Return different responses for consecutive calls mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.users_client, "get_lists_members") + method = getattr(self.users_client, "get_bookmarks") test_cursor = cursor(method, "test_id", max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" @@ -925,8 +1493,8 @@ def test_get_lists_members_cursor_pages(self): assert len(second_data) == 1, "Second page should have 1 item" - def test_get_lists_members_cursor_items(self): - """Test pagination with items() for get_lists_members.""" + def test_get_bookmarks_cursor_items(self): + """Test pagination with items() for get_bookmarks.""" with patch.object(self.client, "session") as mock_session: # Mock response with paginated data mock_response = Mock() @@ -945,7 +1513,7 @@ def test_get_lists_members_cursor_items(self): mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.users_client, "get_lists_members") + method = getattr(self.users_client, "get_bookmarks") test_cursor = cursor(method, "test_id", max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items assert len(items) == 3, f"Should get 3 items, got {len(items)}" @@ -956,15 +1524,15 @@ def test_get_lists_members_cursor_items(self): ), "Items should have 'id' field" - def test_get_lists_members_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_lists_members.""" + def test_get_bookmarks_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_bookmarks.""" with patch.object(self.client, "session") as mock_session: mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.users_client, "get_lists_members") + method = getattr(self.users_client, "get_bookmarks") # Test with max_results parameter test_cursor = cursor(method, "test_id", max_results=5) list(test_cursor.pages(1)) # Trigger one request @@ -1017,20 +1585,20 @@ def test_get_lists_members_pagination_parameters(self): ), "Pagination token should be passed correctly" - def test_get_posts_reposted_by_cursor_creation(self): - """Test that get_posts_reposted_by can be used with Cursor.""" - method = getattr(self.users_client, "get_posts_reposted_by") + def test_get_following_cursor_creation(self): + """Test that get_following can be used with Cursor.""" + method = getattr(self.users_client, "get_following") # Should be able to create cursor without error try: test_cursor = cursor(method, "test_id", max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method getPostsRepostedBy should support pagination") + pytest.fail(f"Method get_following should support pagination") - def test_get_posts_reposted_by_cursor_pages(self): - """Test pagination with pages() for get_posts_reposted_by.""" + def test_get_following_cursor_pages(self): + """Test pagination with pages() for get_following.""" with patch.object(self.client, "session") as mock_session: # Mock first page response first_page_response = Mock() @@ -1051,7 +1619,7 @@ def test_get_posts_reposted_by_cursor_pages(self): # Return different responses for consecutive calls mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.users_client, "get_posts_reposted_by") + method = getattr(self.users_client, "get_following") test_cursor = cursor(method, "test_id", max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" @@ -1067,8 +1635,8 @@ def test_get_posts_reposted_by_cursor_pages(self): assert len(second_data) == 1, "Second page should have 1 item" - def test_get_posts_reposted_by_cursor_items(self): - """Test pagination with items() for get_posts_reposted_by.""" + def test_get_following_cursor_items(self): + """Test pagination with items() for get_following.""" with patch.object(self.client, "session") as mock_session: # Mock response with paginated data mock_response = Mock() @@ -1087,7 +1655,7 @@ def test_get_posts_reposted_by_cursor_items(self): mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.users_client, "get_posts_reposted_by") + method = getattr(self.users_client, "get_following") test_cursor = cursor(method, "test_id", max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items assert len(items) == 3, f"Should get 3 items, got {len(items)}" @@ -1098,15 +1666,15 @@ def test_get_posts_reposted_by_cursor_items(self): ), "Items should have 'id' field" - def test_get_posts_reposted_by_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_posts_reposted_by.""" + def test_get_following_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_following.""" with patch.object(self.client, "session") as mock_session: mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.users_client, "get_posts_reposted_by") + method = getattr(self.users_client, "get_following") # Test with max_results parameter test_cursor = cursor(method, "test_id", max_results=5) list(test_cursor.pages(1)) # Trigger one request @@ -1159,20 +1727,20 @@ def test_get_posts_reposted_by_pagination_parameters(self): ), "Pagination token should be passed correctly" - def test_get_posts_liking_users_cursor_creation(self): - """Test that get_posts_liking_users can be used with Cursor.""" - method = getattr(self.users_client, "get_posts_liking_users") + def test_get_blocking_cursor_creation(self): + """Test that get_blocking can be used with Cursor.""" + method = getattr(self.users_client, "get_blocking") # Should be able to create cursor without error try: test_cursor = cursor(method, "test_id", max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method getPostsLikingUsers should support pagination") + pytest.fail(f"Method get_blocking should support pagination") - def test_get_posts_liking_users_cursor_pages(self): - """Test pagination with pages() for get_posts_liking_users.""" + def test_get_blocking_cursor_pages(self): + """Test pagination with pages() for get_blocking.""" with patch.object(self.client, "session") as mock_session: # Mock first page response first_page_response = Mock() @@ -1193,7 +1761,7 @@ def test_get_posts_liking_users_cursor_pages(self): # Return different responses for consecutive calls mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.users_client, "get_posts_liking_users") + method = getattr(self.users_client, "get_blocking") test_cursor = cursor(method, "test_id", max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" @@ -1209,8 +1777,8 @@ def test_get_posts_liking_users_cursor_pages(self): assert len(second_data) == 1, "Second page should have 1 item" - def test_get_posts_liking_users_cursor_items(self): - """Test pagination with items() for get_posts_liking_users.""" + def test_get_blocking_cursor_items(self): + """Test pagination with items() for get_blocking.""" with patch.object(self.client, "session") as mock_session: # Mock response with paginated data mock_response = Mock() @@ -1229,7 +1797,7 @@ def test_get_posts_liking_users_cursor_items(self): mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.users_client, "get_posts_liking_users") + method = getattr(self.users_client, "get_blocking") test_cursor = cursor(method, "test_id", max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items assert len(items) == 3, f"Should get 3 items, got {len(items)}" @@ -1240,15 +1808,15 @@ def test_get_posts_liking_users_cursor_items(self): ), "Items should have 'id' field" - def test_get_posts_liking_users_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_posts_liking_users.""" + def test_get_blocking_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_blocking.""" with patch.object(self.client, "session") as mock_session: mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.users_client, "get_posts_liking_users") + method = getattr(self.users_client, "get_blocking") # Test with max_results parameter test_cursor = cursor(method, "test_id", max_results=5) list(test_cursor.pages(1)) # Trigger one request @@ -1301,20 +1869,20 @@ def test_get_posts_liking_users_pagination_parameters(self): ), "Pagination token should be passed correctly" - def test_get_users_followers_cursor_creation(self): - """Test that get_users_followers can be used with Cursor.""" - method = getattr(self.users_client, "get_users_followers") + def test_get_followers_cursor_creation(self): + """Test that get_followers can be used with Cursor.""" + method = getattr(self.users_client, "get_followers") # Should be able to create cursor without error try: test_cursor = cursor(method, "test_id", max_results=10) assert test_cursor is not None assert isinstance(test_cursor, Cursor) except PaginationError: - pytest.fail(f"Method getUsersFollowers should support pagination") + pytest.fail(f"Method get_followers should support pagination") - def test_get_users_followers_cursor_pages(self): - """Test pagination with pages() for get_users_followers.""" + def test_get_followers_cursor_pages(self): + """Test pagination with pages() for get_followers.""" with patch.object(self.client, "session") as mock_session: # Mock first page response first_page_response = Mock() @@ -1335,7 +1903,7 @@ def test_get_users_followers_cursor_pages(self): # Return different responses for consecutive calls mock_session.get.side_effect = [first_page_response, second_page_response] # Test pagination - method = getattr(self.users_client, "get_users_followers") + method = getattr(self.users_client, "get_followers") test_cursor = cursor(method, "test_id", max_results=2) pages = list(test_cursor.pages(2)) # Limit to 2 pages assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" @@ -1351,8 +1919,8 @@ def test_get_users_followers_cursor_pages(self): assert len(second_data) == 1, "Second page should have 1 item" - def test_get_users_followers_cursor_items(self): - """Test pagination with items() for get_users_followers.""" + def test_get_followers_cursor_items(self): + """Test pagination with items() for get_followers.""" with patch.object(self.client, "session") as mock_session: # Mock response with paginated data mock_response = Mock() @@ -1371,7 +1939,7 @@ def test_get_users_followers_cursor_items(self): mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response # Test item iteration - method = getattr(self.users_client, "get_users_followers") + method = getattr(self.users_client, "get_followers") test_cursor = cursor(method, "test_id", max_results=10) items = list(test_cursor.items(5)) # Limit to 5 items assert len(items) == 3, f"Should get 3 items, got {len(items)}" @@ -1382,15 +1950,15 @@ def test_get_users_followers_cursor_items(self): ), "Items should have 'id' field" - def test_get_users_followers_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_followers.""" + def test_get_followers_pagination_parameters(self): + """Test that pagination parameters are handled correctly for get_followers.""" with patch.object(self.client, "session") as mock_session: mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = {"data": [], "meta": {"result_count": 0}} mock_response.raise_for_status.return_value = None mock_session.get.return_value = mock_response - method = getattr(self.users_client, "get_users_followers") + method = getattr(self.users_client, "get_followers") # Test with max_results parameter test_cursor = cursor(method, "test_id", max_results=5) list(test_cursor.pages(1)) # Trigger one request @@ -1453,7 +2021,7 @@ def test_pagination_edge_cases(self): empty_response.raise_for_status.return_value = None mock_session.get.return_value = empty_response # Pick first paginatable method for testing - method = getattr(self.users_client, "get_lists_followers") + method = getattr(self.users_client, "get_followed_lists") test_cursor = cursor(method, "test_id", max_results=10) # Should handle empty responses gracefully pages = list(test_cursor.pages(1)) diff --git a/xdk/python/tests/users/test_structure.py b/xdk/python/tests/users/test_structure.py index 9af18728..6bf84bd6 100644 --- a/xdk/python/tests/users/test_structure.py +++ b/xdk/python/tests/users/test_structure.py @@ -1,8 +1,8 @@ """ -Auto-generated structural tests for Users client. +Auto-generated structural tests for {"class_name": "Users", "display_name": "users", "import_name": "users", "original": ["users"], "property_name": "users"} client. This module contains tests that validate the structure and API surface -of the Users client. These tests ensure that all expected methods +of the {"class_name": "Users", "display_name": "users", "import_name": "users", "original": ["users"], "property_name": "users"} client. These tests ensure that all expected methods exist and have the correct signatures. Generated automatically - do not edit manually. @@ -25,22 +25,22 @@ def setup_class(self): self.users_client = getattr(self.client, "users") - def test_get_lists_followers_exists(self): - """Test that get_lists_followers method exists with correct signature.""" + def test_get_followed_lists_exists(self): + """Test that get_followed_lists method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_lists_followers", None) + method = getattr(UsersClient, "get_followed_lists", None) assert ( method is not None - ), f"Method get_lists_followers does not exist on UsersClient" + ), f"Method get_followed_lists does not exist on UsersClient" # Check method is callable - assert callable(method), f"get_lists_followers is not callable" + assert callable(method), f"get_followed_lists is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"get_lists_followers should have at least 'self' parameter" + ), f"get_followed_lists should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -51,7 +51,7 @@ def test_get_lists_followers_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_lists_followers" + ), f"Required parameter '{required_param}' missing from get_followed_lists" # Check optional parameters have defaults (excluding 'self') optional_params = [ "max_results", @@ -65,19 +65,19 @@ def test_get_lists_followers_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_lists_followers_return_annotation(self): - """Test that get_lists_followers has proper return type annotation.""" - method = getattr(UsersClient, "get_lists_followers") + def test_get_followed_lists_return_annotation(self): + """Test that get_followed_lists has proper return type annotation.""" + method = getattr(UsersClient, "get_followed_lists") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_lists_followers should have return type annotation" + ), f"Method get_followed_lists should have return type annotation" - def test_get_lists_followers_pagination_params(self): - """Test that get_lists_followers has pagination parameters.""" - method = getattr(UsersClient, "get_lists_followers") + def test_get_followed_lists_pagination_params(self): + """Test that get_followed_lists has pagination parameters.""" + method = getattr(UsersClient, "get_followed_lists") sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have pagination-related parameters @@ -91,25 +91,25 @@ def test_get_lists_followers_pagination_params(self): has_pagination_param = any(param in params for param in pagination_params) assert ( has_pagination_param - ), f"Paginated method get_lists_followers should have pagination parameters" + ), f"Paginated method get_followed_lists should have pagination parameters" - def test_get_users_muting_exists(self): - """Test that get_users_muting method exists with correct signature.""" + def test_get_list_memberships_exists(self): + """Test that get_list_memberships method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_users_muting", None) + method = getattr(UsersClient, "get_list_memberships", None) assert ( method is not None - ), f"Method get_users_muting does not exist on UsersClient" + ), f"Method get_list_memberships does not exist on UsersClient" # Check method is callable - assert callable(method), f"get_users_muting is not callable" + assert callable(method), f"get_list_memberships is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"get_users_muting should have at least 'self' parameter" + ), f"get_list_memberships should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -120,7 +120,7 @@ def test_get_users_muting_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_muting" + ), f"Required parameter '{required_param}' missing from get_list_memberships" # Check optional parameters have defaults (excluding 'self') optional_params = [ "max_results", @@ -134,19 +134,19 @@ def test_get_users_muting_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_muting_return_annotation(self): - """Test that get_users_muting has proper return type annotation.""" - method = getattr(UsersClient, "get_users_muting") + def test_get_list_memberships_return_annotation(self): + """Test that get_list_memberships has proper return type annotation.""" + method = getattr(UsersClient, "get_list_memberships") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_muting should have return type annotation" + ), f"Method get_list_memberships should have return type annotation" - def test_get_users_muting_pagination_params(self): - """Test that get_users_muting has pagination parameters.""" - method = getattr(UsersClient, "get_users_muting") + def test_get_list_memberships_pagination_params(self): + """Test that get_list_memberships has pagination parameters.""" + method = getattr(UsersClient, "get_list_memberships") sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have pagination-related parameters @@ -160,34 +160,39 @@ def test_get_users_muting_pagination_params(self): has_pagination_param = any(param in params for param in pagination_params) assert ( has_pagination_param - ), f"Paginated method get_users_muting should have pagination parameters" + ), f"Paginated method get_list_memberships should have pagination parameters" - def test_mute_user_exists(self): - """Test that mute_user method exists with correct signature.""" + def test_get_reposts_of_me_exists(self): + """Test that get_reposts_of_me method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "mute_user", None) - assert method is not None, f"Method mute_user does not exist on UsersClient" + method = getattr(UsersClient, "get_reposts_of_me", None) + assert ( + method is not None + ), f"Method get_reposts_of_me does not exist on UsersClient" # Check method is callable - assert callable(method), f"mute_user is not callable" + assert callable(method), f"get_reposts_of_me is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"mute_user should have at least 'self' parameter" + assert ( + len(params) >= 1 + ), f"get_reposts_of_me should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] + required_params = [] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from mute_user" + ), f"Required parameter '{required_param}' missing from get_reposts_of_me" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "max_results", + "pagination_token", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -196,82 +201,62 @@ def test_mute_user_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_mute_user_return_annotation(self): - """Test that mute_user has proper return type annotation.""" - method = getattr(UsersClient, "mute_user") + def test_get_reposts_of_me_return_annotation(self): + """Test that get_reposts_of_me has proper return type annotation.""" + method = getattr(UsersClient, "get_reposts_of_me") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method mute_user should have return type annotation" + ), f"Method get_reposts_of_me should have return type annotation" - def test_get_my_user_exists(self): - """Test that get_my_user method exists with correct signature.""" - # Check method exists - method = getattr(UsersClient, "get_my_user", None) - assert method is not None, f"Method get_my_user does not exist on UsersClient" - # Check method is callable - assert callable(method), f"get_my_user is not callable" - # Check method signature + def test_get_reposts_of_me_pagination_params(self): + """Test that get_reposts_of_me has pagination parameters.""" + method = getattr(UsersClient, "get_reposts_of_me") sig = inspect.signature(method) params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"get_my_user should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_my_user" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_my_user_return_annotation(self): - """Test that get_my_user has proper return type annotation.""" - method = getattr(UsersClient, "get_my_user") - sig = inspect.signature(method) - # Check return annotation exists + # Should have pagination-related parameters + pagination_params = [ + "pagination_token", + "max_results", + "next_token", + "cursor", + "limit", + ] + has_pagination_param = any(param in params for param in pagination_params) assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_my_user should have return type annotation" + has_pagination_param + ), f"Paginated method get_reposts_of_me should have pagination parameters" - def test_get_users_reposts_of_me_exists(self): - """Test that get_users_reposts_of_me method exists with correct signature.""" + def test_get_owned_lists_exists(self): + """Test that get_owned_lists method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_users_reposts_of_me", None) + method = getattr(UsersClient, "get_owned_lists", None) assert ( method is not None - ), f"Method get_users_reposts_of_me does not exist on UsersClient" + ), f"Method get_owned_lists does not exist on UsersClient" # Check method is callable - assert callable(method), f"get_users_reposts_of_me is not callable" + assert callable(method), f"get_owned_lists is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"get_users_reposts_of_me should have at least 'self' parameter" + ), f"get_owned_lists should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [] + required_params = [ + "id", + ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_reposts_of_me" + ), f"Required parameter '{required_param}' missing from get_owned_lists" # Check optional parameters have defaults (excluding 'self') optional_params = [ "max_results", @@ -285,19 +270,19 @@ def test_get_users_reposts_of_me_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_reposts_of_me_return_annotation(self): - """Test that get_users_reposts_of_me has proper return type annotation.""" - method = getattr(UsersClient, "get_users_reposts_of_me") + def test_get_owned_lists_return_annotation(self): + """Test that get_owned_lists has proper return type annotation.""" + method = getattr(UsersClient, "get_owned_lists") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_reposts_of_me should have return type annotation" + ), f"Method get_owned_lists should have return type annotation" - def test_get_users_reposts_of_me_pagination_params(self): - """Test that get_users_reposts_of_me has pagination parameters.""" - method = getattr(UsersClient, "get_users_reposts_of_me") + def test_get_owned_lists_pagination_params(self): + """Test that get_owned_lists has pagination parameters.""" + method = getattr(UsersClient, "get_owned_lists") sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have pagination-related parameters @@ -311,36 +296,41 @@ def test_get_users_reposts_of_me_pagination_params(self): has_pagination_param = any(param in params for param in pagination_params) assert ( has_pagination_param - ), f"Paginated method get_users_reposts_of_me should have pagination parameters" + ), f"Paginated method get_owned_lists should have pagination parameters" - def test_search_users_exists(self): - """Test that search_users method exists with correct signature.""" + def test_get_posts_exists(self): + """Test that get_posts method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "search_users", None) - assert method is not None, f"Method search_users does not exist on UsersClient" + method = getattr(UsersClient, "get_posts", None) + assert method is not None, f"Method get_posts does not exist on UsersClient" # Check method is callable - assert callable(method), f"search_users is not callable" + assert callable(method), f"get_posts is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"search_users should have at least 'self' parameter" + assert len(params) >= 1, f"get_posts should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "query", + "id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from search_users" + ), f"Required parameter '{required_param}' missing from get_posts" # Check optional parameters have defaults (excluding 'self') optional_params = [ + "since_id", + "until_id", "max_results", - "next_token", + "pagination_token", + "exclude", + "start_time", + "end_time", ] for optional_param in optional_params: if optional_param in params: @@ -350,19 +340,19 @@ def test_search_users_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_search_users_return_annotation(self): - """Test that search_users has proper return type annotation.""" - method = getattr(UsersClient, "search_users") + def test_get_posts_return_annotation(self): + """Test that get_posts has proper return type annotation.""" + method = getattr(UsersClient, "get_posts") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method search_users should have return type annotation" + ), f"Method get_posts should have return type annotation" - def test_search_users_pagination_params(self): - """Test that search_users has pagination parameters.""" - method = getattr(UsersClient, "search_users") + def test_get_posts_pagination_params(self): + """Test that get_posts has pagination parameters.""" + method = getattr(UsersClient, "get_posts") sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have pagination-related parameters @@ -376,38 +366,41 @@ def test_search_users_pagination_params(self): has_pagination_param = any(param in params for param in pagination_params) assert ( has_pagination_param - ), f"Paginated method search_users should have pagination parameters" + ), f"Paginated method get_posts should have pagination parameters" - def test_get_users_by_ids_exists(self): - """Test that get_users_by_ids method exists with correct signature.""" + def test_get_liked_posts_exists(self): + """Test that get_liked_posts method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_users_by_ids", None) + method = getattr(UsersClient, "get_liked_posts", None) assert ( method is not None - ), f"Method get_users_by_ids does not exist on UsersClient" + ), f"Method get_liked_posts does not exist on UsersClient" # Check method is callable - assert callable(method), f"get_users_by_ids is not callable" + assert callable(method), f"get_liked_posts is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"get_users_by_ids should have at least 'self' parameter" + ), f"get_liked_posts should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "ids", + "id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_by_ids" + ), f"Required parameter '{required_param}' missing from get_liked_posts" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "max_results", + "pagination_token", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -416,32 +409,47 @@ def test_get_users_by_ids_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_by_ids_return_annotation(self): - """Test that get_users_by_ids has proper return type annotation.""" - method = getattr(UsersClient, "get_users_by_ids") + def test_get_liked_posts_return_annotation(self): + """Test that get_liked_posts has proper return type annotation.""" + method = getattr(UsersClient, "get_liked_posts") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_by_ids should have return type annotation" + ), f"Method get_liked_posts should have return type annotation" - def test_get_users_blocking_exists(self): - """Test that get_users_blocking method exists with correct signature.""" - # Check method exists - method = getattr(UsersClient, "get_users_blocking", None) + def test_get_liked_posts_pagination_params(self): + """Test that get_liked_posts has pagination parameters.""" + method = getattr(UsersClient, "get_liked_posts") + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have pagination-related parameters + pagination_params = [ + "pagination_token", + "max_results", + "next_token", + "cursor", + "limit", + ] + has_pagination_param = any(param in params for param in pagination_params) assert ( - method is not None - ), f"Method get_users_blocking does not exist on UsersClient" + has_pagination_param + ), f"Paginated method get_liked_posts should have pagination parameters" + + + def test_get_timeline_exists(self): + """Test that get_timeline method exists with correct signature.""" + # Check method exists + method = getattr(UsersClient, "get_timeline", None) + assert method is not None, f"Method get_timeline does not exist on UsersClient" # Check method is callable - assert callable(method), f"get_users_blocking is not callable" + assert callable(method), f"get_timeline is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_blocking should have at least 'self' parameter" + assert len(params) >= 1, f"get_timeline should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -452,11 +460,16 @@ def test_get_users_blocking_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_blocking" + ), f"Required parameter '{required_param}' missing from get_timeline" # Check optional parameters have defaults (excluding 'self') optional_params = [ + "since_id", + "until_id", "max_results", "pagination_token", + "exclude", + "start_time", + "end_time", ] for optional_param in optional_params: if optional_param in params: @@ -466,19 +479,19 @@ def test_get_users_blocking_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_blocking_return_annotation(self): - """Test that get_users_blocking has proper return type annotation.""" - method = getattr(UsersClient, "get_users_blocking") + def test_get_timeline_return_annotation(self): + """Test that get_timeline has proper return type annotation.""" + method = getattr(UsersClient, "get_timeline") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_blocking should have return type annotation" + ), f"Method get_timeline should have return type annotation" - def test_get_users_blocking_pagination_params(self): - """Test that get_users_blocking has pagination parameters.""" - method = getattr(UsersClient, "get_users_blocking") + def test_get_timeline_pagination_params(self): + """Test that get_timeline has pagination parameters.""" + method = getattr(UsersClient, "get_timeline") sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have pagination-related parameters @@ -492,36 +505,36 @@ def test_get_users_blocking_pagination_params(self): has_pagination_param = any(param in params for param in pagination_params) assert ( has_pagination_param - ), f"Paginated method get_users_blocking should have pagination parameters" + ), f"Paginated method get_timeline should have pagination parameters" - def test_block_users_dms_exists(self): - """Test that block_users_dms method exists with correct signature.""" + def test_get_by_usernames_exists(self): + """Test that get_by_usernames method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "block_users_dms", None) + method = getattr(UsersClient, "get_by_usernames", None) assert ( method is not None - ), f"Method block_users_dms does not exist on UsersClient" + ), f"Method get_by_usernames does not exist on UsersClient" # Check method is callable - assert callable(method), f"block_users_dms is not callable" + assert callable(method), f"get_by_usernames is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter assert ( len(params) >= 1 - ), f"block_users_dms should have at least 'self' parameter" + ), f"get_by_usernames should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "id", + "usernames", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from block_users_dms" + ), f"Required parameter '{required_param}' missing from get_by_usernames" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -532,45 +545,48 @@ def test_block_users_dms_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_block_users_dms_return_annotation(self): - """Test that block_users_dms has proper return type annotation.""" - method = getattr(UsersClient, "block_users_dms") + def test_get_by_usernames_return_annotation(self): + """Test that get_by_usernames has proper return type annotation.""" + method = getattr(UsersClient, "get_by_usernames") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method block_users_dms should have return type annotation" + ), f"Method get_by_usernames should have return type annotation" - def test_get_users_by_username_exists(self): - """Test that get_users_by_username method exists with correct signature.""" + def test_get_mentions_exists(self): + """Test that get_mentions method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_users_by_username", None) - assert ( - method is not None - ), f"Method get_users_by_username does not exist on UsersClient" + method = getattr(UsersClient, "get_mentions", None) + assert method is not None, f"Method get_mentions does not exist on UsersClient" # Check method is callable - assert callable(method), f"get_users_by_username is not callable" + assert callable(method), f"get_mentions is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_by_username should have at least 'self' parameter" + assert len(params) >= 1, f"get_mentions should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "username", + "id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_by_username" + ), f"Required parameter '{required_param}' missing from get_mentions" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "since_id", + "until_id", + "max_results", + "pagination_token", + "start_time", + "end_time", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -579,47 +595,62 @@ def test_get_users_by_username_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_by_username_return_annotation(self): - """Test that get_users_by_username has proper return type annotation.""" - method = getattr(UsersClient, "get_users_by_username") + def test_get_mentions_return_annotation(self): + """Test that get_mentions has proper return type annotation.""" + method = getattr(UsersClient, "get_mentions") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_by_username should have return type annotation" + ), f"Method get_mentions should have return type annotation" - def test_get_users_following_exists(self): - """Test that get_users_following method exists with correct signature.""" - # Check method exists - method = getattr(UsersClient, "get_users_following", None) + def test_get_mentions_pagination_params(self): + """Test that get_mentions has pagination parameters.""" + method = getattr(UsersClient, "get_mentions") + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have pagination-related parameters + pagination_params = [ + "pagination_token", + "max_results", + "next_token", + "cursor", + "limit", + ] + has_pagination_param = any(param in params for param in pagination_params) assert ( - method is not None - ), f"Method get_users_following does not exist on UsersClient" + has_pagination_param + ), f"Paginated method get_mentions should have pagination parameters" + + + def test_search_exists(self): + """Test that search method exists with correct signature.""" + # Check method exists + method = getattr(UsersClient, "search", None) + assert method is not None, f"Method search does not exist on UsersClient" # Check method is callable - assert callable(method), f"get_users_following is not callable" + assert callable(method), f"search is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_following should have at least 'self' parameter" + assert len(params) >= 1, f"search should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "id", + "query", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_following" + ), f"Required parameter '{required_param}' missing from search" # Check optional parameters have defaults (excluding 'self') optional_params = [ "max_results", - "pagination_token", + "next_token", ] for optional_param in optional_params: if optional_param in params: @@ -629,19 +660,19 @@ def test_get_users_following_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_following_return_annotation(self): - """Test that get_users_following has proper return type annotation.""" - method = getattr(UsersClient, "get_users_following") + def test_search_return_annotation(self): + """Test that search has proper return type annotation.""" + method = getattr(UsersClient, "search") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_following should have return type annotation" + ), f"Method search should have return type annotation" - def test_get_users_following_pagination_params(self): - """Test that get_users_following has pagination parameters.""" - method = getattr(UsersClient, "get_users_following") + def test_search_pagination_params(self): + """Test that search has pagination parameters.""" + method = getattr(UsersClient, "search") sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have pagination-related parameters @@ -655,21 +686,21 @@ def test_get_users_following_pagination_params(self): has_pagination_param = any(param in params for param in pagination_params) assert ( has_pagination_param - ), f"Paginated method get_users_following should have pagination parameters" + ), f"Paginated method search should have pagination parameters" - def test_follow_user_exists(self): - """Test that follow_user method exists with correct signature.""" + def test_get_muting_exists(self): + """Test that get_muting method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "follow_user", None) - assert method is not None, f"Method follow_user does not exist on UsersClient" + method = getattr(UsersClient, "get_muting", None) + assert method is not None, f"Method get_muting does not exist on UsersClient" # Check method is callable - assert callable(method), f"follow_user is not callable" + assert callable(method), f"get_muting is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"follow_user should have at least 'self' parameter" + assert len(params) >= 1, f"get_muting should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -680,9 +711,12 @@ def test_follow_user_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from follow_user" + ), f"Required parameter '{required_param}' missing from get_muting" # Check optional parameters have defaults (excluding 'self') - optional_params = [] + optional_params = [ + "max_results", + "pagination_token", + ] for optional_param in optional_params: if optional_param in params: param_obj = sig.parameters[optional_param] @@ -691,40 +725,58 @@ def test_follow_user_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_follow_user_return_annotation(self): - """Test that follow_user has proper return type annotation.""" - method = getattr(UsersClient, "follow_user") + def test_get_muting_return_annotation(self): + """Test that get_muting has proper return type annotation.""" + method = getattr(UsersClient, "get_muting") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method follow_user should have return type annotation" + ), f"Method get_muting should have return type annotation" - def test_unmute_user_exists(self): - """Test that unmute_user method exists with correct signature.""" + def test_get_muting_pagination_params(self): + """Test that get_muting has pagination parameters.""" + method = getattr(UsersClient, "get_muting") + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have pagination-related parameters + pagination_params = [ + "pagination_token", + "max_results", + "next_token", + "cursor", + "limit", + ] + has_pagination_param = any(param in params for param in pagination_params) + assert ( + has_pagination_param + ), f"Paginated method get_muting should have pagination parameters" + + + def test_mute_user_exists(self): + """Test that mute_user method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "unmute_user", None) - assert method is not None, f"Method unmute_user does not exist on UsersClient" + method = getattr(UsersClient, "mute_user", None) + assert method is not None, f"Method mute_user does not exist on UsersClient" # Check method is callable - assert callable(method), f"unmute_user is not callable" + assert callable(method), f"mute_user is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"unmute_user should have at least 'self' parameter" + assert len(params) >= 1, f"mute_user should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "source_user_id", - "target_user_id", + "id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from unmute_user" + ), f"Required parameter '{required_param}' missing from mute_user" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -735,32 +787,28 @@ def test_unmute_user_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_unmute_user_return_annotation(self): - """Test that unmute_user has proper return type annotation.""" - method = getattr(UsersClient, "unmute_user") + def test_mute_user_return_annotation(self): + """Test that mute_user has proper return type annotation.""" + method = getattr(UsersClient, "mute_user") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method unmute_user should have return type annotation" + ), f"Method mute_user should have return type annotation" - def test_unblock_users_dms_exists(self): - """Test that unblock_users_dms method exists with correct signature.""" + def test_unblock_dms_exists(self): + """Test that unblock_dms method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "unblock_users_dms", None) - assert ( - method is not None - ), f"Method unblock_users_dms does not exist on UsersClient" + method = getattr(UsersClient, "unblock_dms", None) + assert method is not None, f"Method unblock_dms does not exist on UsersClient" # Check method is callable - assert callable(method), f"unblock_users_dms is not callable" + assert callable(method), f"unblock_dms is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"unblock_users_dms should have at least 'self' parameter" + assert len(params) >= 1, f"unblock_dms should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -771,7 +819,7 @@ def test_unblock_users_dms_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from unblock_users_dms" + ), f"Required parameter '{required_param}' missing from unblock_dms" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -782,28 +830,28 @@ def test_unblock_users_dms_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_unblock_users_dms_return_annotation(self): - """Test that unblock_users_dms has proper return type annotation.""" - method = getattr(UsersClient, "unblock_users_dms") + def test_unblock_dms_return_annotation(self): + """Test that unblock_dms has proper return type annotation.""" + method = getattr(UsersClient, "unblock_dms") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method unblock_users_dms should have return type annotation" + ), f"Method unblock_dms should have return type annotation" - def test_unfollow_user_exists(self): - """Test that unfollow_user method exists with correct signature.""" + def test_unmute_user_exists(self): + """Test that unmute_user method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "unfollow_user", None) - assert method is not None, f"Method unfollow_user does not exist on UsersClient" + method = getattr(UsersClient, "unmute_user", None) + assert method is not None, f"Method unmute_user does not exist on UsersClient" # Check method is callable - assert callable(method), f"unfollow_user is not callable" + assert callable(method), f"unmute_user is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"unfollow_user should have at least 'self' parameter" + assert len(params) >= 1, f"unmute_user should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -815,7 +863,7 @@ def test_unfollow_user_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from unfollow_user" + ), f"Required parameter '{required_param}' missing from unmute_user" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -826,32 +874,28 @@ def test_unfollow_user_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_unfollow_user_return_annotation(self): - """Test that unfollow_user has proper return type annotation.""" - method = getattr(UsersClient, "unfollow_user") + def test_unmute_user_return_annotation(self): + """Test that unmute_user has proper return type annotation.""" + method = getattr(UsersClient, "unmute_user") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method unfollow_user should have return type annotation" + ), f"Method unmute_user should have return type annotation" - def test_get_lists_members_exists(self): - """Test that get_lists_members method exists with correct signature.""" + def test_get_bookmarks_exists(self): + """Test that get_bookmarks method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_lists_members", None) - assert ( - method is not None - ), f"Method get_lists_members does not exist on UsersClient" + method = getattr(UsersClient, "get_bookmarks", None) + assert method is not None, f"Method get_bookmarks does not exist on UsersClient" # Check method is callable - assert callable(method), f"get_lists_members is not callable" + assert callable(method), f"get_bookmarks is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_lists_members should have at least 'self' parameter" + assert len(params) >= 1, f"get_bookmarks should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -862,7 +906,7 @@ def test_get_lists_members_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_lists_members" + ), f"Required parameter '{required_param}' missing from get_bookmarks" # Check optional parameters have defaults (excluding 'self') optional_params = [ "max_results", @@ -876,19 +920,19 @@ def test_get_lists_members_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_lists_members_return_annotation(self): - """Test that get_lists_members has proper return type annotation.""" - method = getattr(UsersClient, "get_lists_members") + def test_get_bookmarks_return_annotation(self): + """Test that get_bookmarks has proper return type annotation.""" + method = getattr(UsersClient, "get_bookmarks") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_lists_members should have return type annotation" + ), f"Method get_bookmarks should have return type annotation" - def test_get_lists_members_pagination_params(self): - """Test that get_lists_members has pagination parameters.""" - method = getattr(UsersClient, "get_lists_members") + def test_get_bookmarks_pagination_params(self): + """Test that get_bookmarks has pagination parameters.""" + method = getattr(UsersClient, "get_bookmarks") sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have pagination-related parameters @@ -902,25 +946,64 @@ def test_get_lists_members_pagination_params(self): has_pagination_param = any(param in params for param in pagination_params) assert ( has_pagination_param - ), f"Paginated method get_lists_members should have pagination parameters" + ), f"Paginated method get_bookmarks should have pagination parameters" - def test_get_posts_reposted_by_exists(self): - """Test that get_posts_reposted_by method exists with correct signature.""" + def test_get_by_ids_exists(self): + """Test that get_by_ids method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_posts_reposted_by", None) - assert ( - method is not None - ), f"Method get_posts_reposted_by does not exist on UsersClient" + method = getattr(UsersClient, "get_by_ids", None) + assert method is not None, f"Method get_by_ids does not exist on UsersClient" # Check method is callable - assert callable(method), f"get_posts_reposted_by is not callable" + assert callable(method), f"get_by_ids is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter + assert len(params) >= 1, f"get_by_ids should have at least 'self' parameter" assert ( - len(params) >= 1 - ), f"get_posts_reposted_by should have at least 'self' parameter" + params[0] == "self" + ), f"First parameter should be 'self', got '{params[0]}'" + # Check required parameters exist (excluding 'self') + required_params = [ + "ids", + ] + for required_param in required_params: + assert ( + required_param in params + ), f"Required parameter '{required_param}' missing from get_by_ids" + # Check optional parameters have defaults (excluding 'self') + optional_params = [] + for optional_param in optional_params: + if optional_param in params: + param_obj = sig.parameters[optional_param] + assert ( + param_obj.default is not inspect.Parameter.empty + ), f"Optional parameter '{optional_param}' should have a default value" + + + def test_get_by_ids_return_annotation(self): + """Test that get_by_ids has proper return type annotation.""" + method = getattr(UsersClient, "get_by_ids") + sig = inspect.signature(method) + # Check return annotation exists + assert ( + sig.return_annotation is not inspect.Signature.empty + ), f"Method get_by_ids should have return type annotation" + + + def test_get_following_exists(self): + """Test that get_following method exists with correct signature.""" + # Check method exists + method = getattr(UsersClient, "get_following", None) + assert method is not None, f"Method get_following does not exist on UsersClient" + # Check method is callable + assert callable(method), f"get_following is not callable" + # Check method signature + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have 'self' as first parameter + assert len(params) >= 1, f"get_following should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -931,7 +1014,7 @@ def test_get_posts_reposted_by_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_posts_reposted_by" + ), f"Required parameter '{required_param}' missing from get_following" # Check optional parameters have defaults (excluding 'self') optional_params = [ "max_results", @@ -945,19 +1028,19 @@ def test_get_posts_reposted_by_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_posts_reposted_by_return_annotation(self): - """Test that get_posts_reposted_by has proper return type annotation.""" - method = getattr(UsersClient, "get_posts_reposted_by") + def test_get_following_return_annotation(self): + """Test that get_following has proper return type annotation.""" + method = getattr(UsersClient, "get_following") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_posts_reposted_by should have return type annotation" + ), f"Method get_following should have return type annotation" - def test_get_posts_reposted_by_pagination_params(self): - """Test that get_posts_reposted_by has pagination parameters.""" - method = getattr(UsersClient, "get_posts_reposted_by") + def test_get_following_pagination_params(self): + """Test that get_following has pagination parameters.""" + method = getattr(UsersClient, "get_following") sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have pagination-related parameters @@ -971,25 +1054,21 @@ def test_get_posts_reposted_by_pagination_params(self): has_pagination_param = any(param in params for param in pagination_params) assert ( has_pagination_param - ), f"Paginated method get_posts_reposted_by should have pagination parameters" + ), f"Paginated method get_following should have pagination parameters" - def test_get_users_by_id_exists(self): - """Test that get_users_by_id method exists with correct signature.""" + def test_follow_user_exists(self): + """Test that follow_user method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_users_by_id", None) - assert ( - method is not None - ), f"Method get_users_by_id does not exist on UsersClient" + method = getattr(UsersClient, "follow_user", None) + assert method is not None, f"Method follow_user does not exist on UsersClient" # Check method is callable - assert callable(method), f"get_users_by_id is not callable" + assert callable(method), f"follow_user is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_by_id should have at least 'self' parameter" + assert len(params) >= 1, f"follow_user should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -1000,7 +1079,7 @@ def test_get_users_by_id_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_by_id" + ), f"Required parameter '{required_param}' missing from follow_user" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -1011,43 +1090,80 @@ def test_get_users_by_id_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_by_id_return_annotation(self): - """Test that get_users_by_id has proper return type annotation.""" - method = getattr(UsersClient, "get_users_by_id") + def test_follow_user_return_annotation(self): + """Test that follow_user has proper return type annotation.""" + method = getattr(UsersClient, "follow_user") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_by_id should have return type annotation" + ), f"Method follow_user should have return type annotation" - def test_get_users_by_usernames_exists(self): - """Test that get_users_by_usernames method exists with correct signature.""" + def test_get_me_exists(self): + """Test that get_me method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_users_by_usernames", None) - assert ( - method is not None - ), f"Method get_users_by_usernames does not exist on UsersClient" + method = getattr(UsersClient, "get_me", None) + assert method is not None, f"Method get_me does not exist on UsersClient" # Check method is callable - assert callable(method), f"get_users_by_usernames is not callable" + assert callable(method), f"get_me is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter + assert len(params) >= 1, f"get_me should have at least 'self' parameter" assert ( - len(params) >= 1 - ), f"get_users_by_usernames should have at least 'self' parameter" + params[0] == "self" + ), f"First parameter should be 'self', got '{params[0]}'" + # Check required parameters exist (excluding 'self') + required_params = [] + for required_param in required_params: + assert ( + required_param in params + ), f"Required parameter '{required_param}' missing from get_me" + # Check optional parameters have defaults (excluding 'self') + optional_params = [] + for optional_param in optional_params: + if optional_param in params: + param_obj = sig.parameters[optional_param] + assert ( + param_obj.default is not inspect.Parameter.empty + ), f"Optional parameter '{optional_param}' should have a default value" + + + def test_get_me_return_annotation(self): + """Test that get_me has proper return type annotation.""" + method = getattr(UsersClient, "get_me") + sig = inspect.signature(method) + # Check return annotation exists + assert ( + sig.return_annotation is not inspect.Signature.empty + ), f"Method get_me should have return type annotation" + + + def test_get_by_id_exists(self): + """Test that get_by_id method exists with correct signature.""" + # Check method exists + method = getattr(UsersClient, "get_by_id", None) + assert method is not None, f"Method get_by_id does not exist on UsersClient" + # Check method is callable + assert callable(method), f"get_by_id is not callable" + # Check method signature + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have 'self' as first parameter + assert len(params) >= 1, f"get_by_id should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') required_params = [ - "usernames", + "id", ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_by_usernames" + ), f"Required parameter '{required_param}' missing from get_by_id" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -1058,32 +1174,28 @@ def test_get_users_by_usernames_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_by_usernames_return_annotation(self): - """Test that get_users_by_usernames has proper return type annotation.""" - method = getattr(UsersClient, "get_users_by_usernames") + def test_get_by_id_return_annotation(self): + """Test that get_by_id has proper return type annotation.""" + method = getattr(UsersClient, "get_by_id") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_by_usernames should have return type annotation" + ), f"Method get_by_id should have return type annotation" - def test_get_posts_liking_users_exists(self): - """Test that get_posts_liking_users method exists with correct signature.""" + def test_get_blocking_exists(self): + """Test that get_blocking method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_posts_liking_users", None) - assert ( - method is not None - ), f"Method get_posts_liking_users does not exist on UsersClient" + method = getattr(UsersClient, "get_blocking", None) + assert method is not None, f"Method get_blocking does not exist on UsersClient" # Check method is callable - assert callable(method), f"get_posts_liking_users is not callable" + assert callable(method), f"get_blocking is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_posts_liking_users should have at least 'self' parameter" + assert len(params) >= 1, f"get_blocking should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -1094,7 +1206,7 @@ def test_get_posts_liking_users_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_posts_liking_users" + ), f"Required parameter '{required_param}' missing from get_blocking" # Check optional parameters have defaults (excluding 'self') optional_params = [ "max_results", @@ -1108,19 +1220,19 @@ def test_get_posts_liking_users_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_posts_liking_users_return_annotation(self): - """Test that get_posts_liking_users has proper return type annotation.""" - method = getattr(UsersClient, "get_posts_liking_users") + def test_get_blocking_return_annotation(self): + """Test that get_blocking has proper return type annotation.""" + method = getattr(UsersClient, "get_blocking") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_posts_liking_users should have return type annotation" + ), f"Method get_blocking should have return type annotation" - def test_get_posts_liking_users_pagination_params(self): - """Test that get_posts_liking_users has pagination parameters.""" - method = getattr(UsersClient, "get_posts_liking_users") + def test_get_blocking_pagination_params(self): + """Test that get_blocking has pagination parameters.""" + method = getattr(UsersClient, "get_blocking") sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have pagination-related parameters @@ -1134,25 +1246,108 @@ def test_get_posts_liking_users_pagination_params(self): has_pagination_param = any(param in params for param in pagination_params) assert ( has_pagination_param - ), f"Paginated method get_posts_liking_users should have pagination parameters" + ), f"Paginated method get_blocking should have pagination parameters" - def test_get_users_followers_exists(self): - """Test that get_users_followers method exists with correct signature.""" + def test_block_dms_exists(self): + """Test that block_dms method exists with correct signature.""" # Check method exists - method = getattr(UsersClient, "get_users_followers", None) + method = getattr(UsersClient, "block_dms", None) + assert method is not None, f"Method block_dms does not exist on UsersClient" + # Check method is callable + assert callable(method), f"block_dms is not callable" + # Check method signature + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have 'self' as first parameter + assert len(params) >= 1, f"block_dms should have at least 'self' parameter" assert ( - method is not None - ), f"Method get_users_followers does not exist on UsersClient" + params[0] == "self" + ), f"First parameter should be 'self', got '{params[0]}'" + # Check required parameters exist (excluding 'self') + required_params = [ + "id", + ] + for required_param in required_params: + assert ( + required_param in params + ), f"Required parameter '{required_param}' missing from block_dms" + # Check optional parameters have defaults (excluding 'self') + optional_params = [] + for optional_param in optional_params: + if optional_param in params: + param_obj = sig.parameters[optional_param] + assert ( + param_obj.default is not inspect.Parameter.empty + ), f"Optional parameter '{optional_param}' should have a default value" + + + def test_block_dms_return_annotation(self): + """Test that block_dms has proper return type annotation.""" + method = getattr(UsersClient, "block_dms") + sig = inspect.signature(method) + # Check return annotation exists + assert ( + sig.return_annotation is not inspect.Signature.empty + ), f"Method block_dms should have return type annotation" + + + def test_unfollow_user_exists(self): + """Test that unfollow_user method exists with correct signature.""" + # Check method exists + method = getattr(UsersClient, "unfollow_user", None) + assert method is not None, f"Method unfollow_user does not exist on UsersClient" # Check method is callable - assert callable(method), f"get_users_followers is not callable" + assert callable(method), f"unfollow_user is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter + assert len(params) >= 1, f"unfollow_user should have at least 'self' parameter" assert ( - len(params) >= 1 - ), f"get_users_followers should have at least 'self' parameter" + params[0] == "self" + ), f"First parameter should be 'self', got '{params[0]}'" + # Check required parameters exist (excluding 'self') + required_params = [ + "source_user_id", + "target_user_id", + ] + for required_param in required_params: + assert ( + required_param in params + ), f"Required parameter '{required_param}' missing from unfollow_user" + # Check optional parameters have defaults (excluding 'self') + optional_params = [] + for optional_param in optional_params: + if optional_param in params: + param_obj = sig.parameters[optional_param] + assert ( + param_obj.default is not inspect.Parameter.empty + ), f"Optional parameter '{optional_param}' should have a default value" + + + def test_unfollow_user_return_annotation(self): + """Test that unfollow_user has proper return type annotation.""" + method = getattr(UsersClient, "unfollow_user") + sig = inspect.signature(method) + # Check return annotation exists + assert ( + sig.return_annotation is not inspect.Signature.empty + ), f"Method unfollow_user should have return type annotation" + + + def test_get_followers_exists(self): + """Test that get_followers method exists with correct signature.""" + # Check method exists + method = getattr(UsersClient, "get_followers", None) + assert method is not None, f"Method get_followers does not exist on UsersClient" + # Check method is callable + assert callable(method), f"get_followers is not callable" + # Check method signature + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have 'self' as first parameter + assert len(params) >= 1, f"get_followers should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" @@ -1163,7 +1358,7 @@ def test_get_users_followers_exists(self): for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_users_followers" + ), f"Required parameter '{required_param}' missing from get_followers" # Check optional parameters have defaults (excluding 'self') optional_params = [ "max_results", @@ -1177,19 +1372,19 @@ def test_get_users_followers_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_users_followers_return_annotation(self): - """Test that get_users_followers has proper return type annotation.""" - method = getattr(UsersClient, "get_users_followers") + def test_get_followers_return_annotation(self): + """Test that get_followers has proper return type annotation.""" + method = getattr(UsersClient, "get_followers") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_followers should have return type annotation" + ), f"Method get_followers should have return type annotation" - def test_get_users_followers_pagination_params(self): - """Test that get_users_followers has pagination parameters.""" - method = getattr(UsersClient, "get_users_followers") + def test_get_followers_pagination_params(self): + """Test that get_followers has pagination parameters.""" + method = getattr(UsersClient, "get_followers") sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have pagination-related parameters @@ -1203,33 +1398,84 @@ def test_get_users_followers_pagination_params(self): has_pagination_param = any(param in params for param in pagination_params) assert ( has_pagination_param - ), f"Paginated method get_users_followers should have pagination parameters" + ), f"Paginated method get_followers should have pagination parameters" + + + def test_get_by_username_exists(self): + """Test that get_by_username method exists with correct signature.""" + # Check method exists + method = getattr(UsersClient, "get_by_username", None) + assert ( + method is not None + ), f"Method get_by_username does not exist on UsersClient" + # Check method is callable + assert callable(method), f"get_by_username is not callable" + # Check method signature + sig = inspect.signature(method) + params = list(sig.parameters.keys()) + # Should have 'self' as first parameter + assert ( + len(params) >= 1 + ), f"get_by_username should have at least 'self' parameter" + assert ( + params[0] == "self" + ), f"First parameter should be 'self', got '{params[0]}'" + # Check required parameters exist (excluding 'self') + required_params = [ + "username", + ] + for required_param in required_params: + assert ( + required_param in params + ), f"Required parameter '{required_param}' missing from get_by_username" + # Check optional parameters have defaults (excluding 'self') + optional_params = [] + for optional_param in optional_params: + if optional_param in params: + param_obj = sig.parameters[optional_param] + assert ( + param_obj.default is not inspect.Parameter.empty + ), f"Optional parameter '{optional_param}' should have a default value" + + + def test_get_by_username_return_annotation(self): + """Test that get_by_username has proper return type annotation.""" + method = getattr(UsersClient, "get_by_username") + sig = inspect.signature(method) + # Check return annotation exists + assert ( + sig.return_annotation is not inspect.Signature.empty + ), f"Method get_by_username should have return type annotation" def test_all_expected_methods_exist(self): """Test that all expected methods exist on the client.""" expected_methods = [ - "get_lists_followers", - "get_users_muting", + "get_followed_lists", + "get_list_memberships", + "get_reposts_of_me", + "get_owned_lists", + "get_posts", + "get_liked_posts", + "get_timeline", + "get_by_usernames", + "get_mentions", + "search", + "get_muting", "mute_user", - "get_my_user", - "get_users_reposts_of_me", - "search_users", - "get_users_by_ids", - "get_users_blocking", - "block_users_dms", - "get_users_by_username", - "get_users_following", - "follow_user", + "unblock_dms", "unmute_user", - "unblock_users_dms", + "get_bookmarks", + "get_by_ids", + "get_following", + "follow_user", + "get_me", + "get_by_id", + "get_blocking", + "block_dms", "unfollow_user", - "get_lists_members", - "get_posts_reposted_by", - "get_users_by_id", - "get_users_by_usernames", - "get_posts_liking_users", - "get_users_followers", + "get_followers", + "get_by_username", ] for expected_method in expected_methods: assert hasattr( diff --git a/xdk/python/tests/webhooks/test_contracts.py b/xdk/python/tests/webhooks/test_contracts.py index c63b9607..a05d3e04 100644 --- a/xdk/python/tests/webhooks/test_contracts.py +++ b/xdk/python/tests/webhooks/test_contracts.py @@ -1,8 +1,8 @@ """ -Auto-generated contract tests for Webhooks client. +Auto-generated contract tests for {"class_name": "Webhooks", "display_name": "webhooks", "import_name": "webhooks", "original": ["webhooks"], "property_name": "webhooks"} client. This module contains tests that validate the request/response contracts -of the Webhooks client against the OpenAPI specification. +of the {"class_name": "Webhooks", "display_name": "webhooks", "import_name": "webhooks", "original": ["webhooks"], "property_name": "webhooks"} client against the OpenAPI specification. Generated automatically - do not edit manually. """ @@ -24,8 +24,8 @@ def setup_class(self): self.webhooks_client = getattr(self.client, "webhooks") - def test_validate_webhooks_request_structure(self): - """Test validate_webhooks request structure.""" + def test_get_request_structure(self): + """Test get request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -34,25 +34,24 @@ def test_validate_webhooks_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.put.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["webhook_id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.webhooks_client, "validate_webhooks") + method = getattr(self.webhooks_client, "get") result = method(**kwargs) # Verify the request was made - mock_session.put.assert_called_once() + mock_session.get.assert_called_once() # Verify request structure - call_args = mock_session.put.call_args + call_args = mock_session.get.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/webhooks/{webhook_id}" + expected_path = "/2/webhooks" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -61,27 +60,27 @@ def test_validate_webhooks_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for validate_webhooks: {e}") + pytest.fail(f"Contract test failed for get: {e}") - def test_validate_webhooks_required_parameters(self): - """Test that validate_webhooks handles parameters correctly.""" - method = getattr(self.webhooks_client, "validate_webhooks") - # Test with missing required parameters - mock the request to avoid network calls + def test_get_required_parameters(self): + """Test that get handles parameters correctly.""" + method = getattr(self.webhooks_client, "get") + # No required parameters, method should be callable without args with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.put.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): + mock_response.status_code = 200 + mock_response.json.return_value = {} + mock_response.raise_for_status.return_value = None + mock_session.get.return_value = mock_response + try: method() + except Exception as e: + pytest.fail(f"Method with no required params should be callable: {e}") - def test_validate_webhooks_response_structure(self): - """Test validate_webhooks response structure validation.""" + def test_get_response_structure(self): + """Test get response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -91,13 +90,12 @@ def test_validate_webhooks_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.put.return_value = mock_response + mock_session.get.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["webhook_id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.webhooks_client, "validate_webhooks") + method = getattr(self.webhooks_client, "get") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -109,8 +107,8 @@ def test_validate_webhooks_response_structure(self): ) - def test_delete_webhooks_request_structure(self): - """Test delete_webhooks request structure.""" + def test_create_request_structure(self): + """Test create request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -119,25 +117,28 @@ def test_delete_webhooks_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters - kwargs["webhook_id"] = "test_value" # Add request body if required + # Import and create proper request model instance + from xdk.webhooks.models import CreateRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = CreateRequest() # Call the method try: - method = getattr(self.webhooks_client, "delete_webhooks") + method = getattr(self.webhooks_client, "create") result = method(**kwargs) # Verify the request was made - mock_session.delete.assert_called_once() + mock_session.post.assert_called_once() # Verify request structure - call_args = mock_session.delete.call_args + call_args = mock_session.post.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/webhooks/{webhook_id}" + expected_path = "/2/webhooks" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -146,12 +147,12 @@ def test_delete_webhooks_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for delete_webhooks: {e}") + pytest.fail(f"Contract test failed for create: {e}") - def test_delete_webhooks_required_parameters(self): - """Test that delete_webhooks handles parameters correctly.""" - method = getattr(self.webhooks_client, "delete_webhooks") + def test_create_required_parameters(self): + """Test that create handles parameters correctly.""" + method = getattr(self.webhooks_client, "create") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -159,14 +160,14 @@ def test_delete_webhooks_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response + mock_session.post.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_delete_webhooks_response_structure(self): - """Test delete_webhooks response structure validation.""" + def test_create_response_structure(self): + """Test create response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -176,13 +177,16 @@ def test_delete_webhooks_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response + mock_session.post.return_value = mock_response # Prepare minimal valid parameters kwargs = {} - kwargs["webhook_id"] = "test" # Add request body if required + # Import and create proper request model instance + from xdk.webhooks.models import CreateRequest + # Create instance with minimal valid data (empty instance should work for most cases) + kwargs["body"] = CreateRequest() # Call method and verify response structure - method = getattr(self.webhooks_client, "delete_webhooks") + method = getattr(self.webhooks_client, "create") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -194,8 +198,8 @@ def test_delete_webhooks_response_structure(self): ) - def test_get_webhooks_request_structure(self): - """Test get_webhooks request structure.""" + def test_validate_request_structure(self): + """Test validate request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -204,24 +208,25 @@ def test_get_webhooks_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.put.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters + kwargs["webhook_id"] = "test_value" # Add request body if required # Call the method try: - method = getattr(self.webhooks_client, "get_webhooks") + method = getattr(self.webhooks_client, "validate") result = method(**kwargs) # Verify the request was made - mock_session.get.assert_called_once() + mock_session.put.assert_called_once() # Verify request structure - call_args = mock_session.get.call_args + call_args = mock_session.put.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/webhooks" + expected_path = "/2/webhooks/{webhook_id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -230,27 +235,27 @@ def test_get_webhooks_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for get_webhooks: {e}") + pytest.fail(f"Contract test failed for validate: {e}") - def test_get_webhooks_required_parameters(self): - """Test that get_webhooks handles parameters correctly.""" - method = getattr(self.webhooks_client, "get_webhooks") - # No required parameters, method should be callable without args + def test_validate_required_parameters(self): + """Test that validate handles parameters correctly.""" + method = getattr(self.webhooks_client, "validate") + # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: + # Mock a 400 response (typical for missing required parameters) mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: + mock_response.status_code = 400 + mock_response.json.return_value = {"error": "Missing required parameters"} + mock_response.raise_for_status.side_effect = Exception("Bad Request") + mock_session.put.return_value = mock_response + # Call without required parameters should either raise locally or via server response + with pytest.raises((TypeError, ValueError, Exception)): method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - def test_get_webhooks_response_structure(self): - """Test get_webhooks response structure validation.""" + def test_validate_response_structure(self): + """Test validate response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -260,12 +265,13 @@ def test_get_webhooks_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response + mock_session.put.return_value = mock_response # Prepare minimal valid parameters kwargs = {} + kwargs["webhook_id"] = "test" # Add request body if required # Call method and verify response structure - method = getattr(self.webhooks_client, "get_webhooks") + method = getattr(self.webhooks_client, "validate") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed @@ -277,8 +283,8 @@ def test_get_webhooks_response_structure(self): ) - def test_create_webhooks_request_structure(self): - """Test create_webhooks request structure.""" + def test_delete_request_structure(self): + """Test delete request structure.""" # Mock the session to capture request details with patch.object(self.client, "session") as mock_session: mock_response = Mock() @@ -287,28 +293,25 @@ def test_create_webhooks_request_structure(self): "data": None, } mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare test parameters kwargs = {} # Add required parameters + kwargs["webhook_id"] = "test_value" # Add request body if required - # Import and create proper request model instance - from xdk.webhooks.models import CreateWebhooksRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateWebhooksRequest() # Call the method try: - method = getattr(self.webhooks_client, "create_webhooks") + method = getattr(self.webhooks_client, "delete") result = method(**kwargs) # Verify the request was made - mock_session.post.assert_called_once() + mock_session.delete.assert_called_once() # Verify request structure - call_args = mock_session.post.call_args + call_args = mock_session.delete.call_args # Check URL structure called_url = ( call_args[0][0] if call_args[0] else call_args[1].get("url", "") ) - expected_path = "/2/webhooks" + expected_path = "/2/webhooks/{webhook_id}" assert expected_path.replace("{", "").replace( "}", "" ) in called_url or any( @@ -317,12 +320,12 @@ def test_create_webhooks_request_structure(self): # Verify response structure assert result is not None, "Method should return a result" except Exception as e: - pytest.fail(f"Contract test failed for create_webhooks: {e}") + pytest.fail(f"Contract test failed for delete: {e}") - def test_create_webhooks_required_parameters(self): - """Test that create_webhooks handles parameters correctly.""" - method = getattr(self.webhooks_client, "create_webhooks") + def test_delete_required_parameters(self): + """Test that delete handles parameters correctly.""" + method = getattr(self.webhooks_client, "delete") # Test with missing required parameters - mock the request to avoid network calls with patch.object(self.client, "session") as mock_session: # Mock a 400 response (typical for missing required parameters) @@ -330,14 +333,14 @@ def test_create_webhooks_required_parameters(self): mock_response.status_code = 400 mock_response.json.return_value = {"error": "Missing required parameters"} mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response + mock_session.delete.return_value = mock_response # Call without required parameters should either raise locally or via server response with pytest.raises((TypeError, ValueError, Exception)): method() - def test_create_webhooks_response_structure(self): - """Test create_webhooks response structure validation.""" + def test_delete_response_structure(self): + """Test delete response structure validation.""" with patch.object(self.client, "session") as mock_session: # Create mock response with expected structure mock_response_data = { @@ -347,16 +350,13 @@ def test_create_webhooks_response_structure(self): mock_response.status_code = 200 mock_response.json.return_value = mock_response_data mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response + mock_session.delete.return_value = mock_response # Prepare minimal valid parameters kwargs = {} + kwargs["webhook_id"] = "test" # Add request body if required - # Import and create proper request model instance - from xdk.webhooks.models import CreateWebhooksRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateWebhooksRequest() # Call method and verify response structure - method = getattr(self.webhooks_client, "create_webhooks") + method = getattr(self.webhooks_client, "delete") result = method(**kwargs) # Verify response object has expected attributes # Optional field - just check it doesn't cause errors if accessed diff --git a/xdk/python/tests/webhooks/test_generic.py b/xdk/python/tests/webhooks/test_generic.py index c5f539a1..8ef24dbd 100644 --- a/xdk/python/tests/webhooks/test_generic.py +++ b/xdk/python/tests/webhooks/test_generic.py @@ -1,5 +1,5 @@ """ -Auto-generated generic tests for Webhooks client. +Auto-generated generic tests for {"class_name": "Webhooks", "display_name": "webhooks", "import_name": "webhooks", "original": ["webhooks"], "property_name": "webhooks"} client. This module contains general tests that validate the overall client functionality, imports, and error handling that don't need to be diff --git a/xdk/python/tests/webhooks/test_structure.py b/xdk/python/tests/webhooks/test_structure.py index b134323c..fc14ed5f 100644 --- a/xdk/python/tests/webhooks/test_structure.py +++ b/xdk/python/tests/webhooks/test_structure.py @@ -1,8 +1,8 @@ """ -Auto-generated structural tests for Webhooks client. +Auto-generated structural tests for {"class_name": "Webhooks", "display_name": "webhooks", "import_name": "webhooks", "original": ["webhooks"], "property_name": "webhooks"} client. This module contains tests that validate the structure and API surface -of the Webhooks client. These tests ensure that all expected methods +of the {"class_name": "Webhooks", "display_name": "webhooks", "import_name": "webhooks", "original": ["webhooks"], "property_name": "webhooks"} client. These tests ensure that all expected methods exist and have the correct signatures. Generated automatically - do not edit manually. @@ -25,33 +25,27 @@ def setup_class(self): self.webhooks_client = getattr(self.client, "webhooks") - def test_validate_webhooks_exists(self): - """Test that validate_webhooks method exists with correct signature.""" + def test_get_exists(self): + """Test that get method exists with correct signature.""" # Check method exists - method = getattr(WebhooksClient, "validate_webhooks", None) - assert ( - method is not None - ), f"Method validate_webhooks does not exist on WebhooksClient" + method = getattr(WebhooksClient, "get", None) + assert method is not None, f"Method get does not exist on WebhooksClient" # Check method is callable - assert callable(method), f"validate_webhooks is not callable" + assert callable(method), f"get is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"validate_webhooks should have at least 'self' parameter" + assert len(params) >= 1, f"get should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [ - "webhook_id", - ] + required_params = [] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from validate_webhooks" + ), f"Required parameter '{required_param}' missing from get" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -62,43 +56,37 @@ def test_validate_webhooks_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_validate_webhooks_return_annotation(self): - """Test that validate_webhooks has proper return type annotation.""" - method = getattr(WebhooksClient, "validate_webhooks") + def test_get_return_annotation(self): + """Test that get has proper return type annotation.""" + method = getattr(WebhooksClient, "get") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method validate_webhooks should have return type annotation" + ), f"Method get should have return type annotation" - def test_delete_webhooks_exists(self): - """Test that delete_webhooks method exists with correct signature.""" + def test_create_exists(self): + """Test that create method exists with correct signature.""" # Check method exists - method = getattr(WebhooksClient, "delete_webhooks", None) - assert ( - method is not None - ), f"Method delete_webhooks does not exist on WebhooksClient" + method = getattr(WebhooksClient, "create", None) + assert method is not None, f"Method create does not exist on WebhooksClient" # Check method is callable - assert callable(method), f"delete_webhooks is not callable" + assert callable(method), f"create is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"delete_webhooks should have at least 'self' parameter" + assert len(params) >= 1, f"create should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [ - "webhook_id", - ] + required_params = [] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from delete_webhooks" + ), f"Required parameter '{required_param}' missing from create" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -109,39 +97,39 @@ def test_delete_webhooks_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_delete_webhooks_return_annotation(self): - """Test that delete_webhooks has proper return type annotation.""" - method = getattr(WebhooksClient, "delete_webhooks") + def test_create_return_annotation(self): + """Test that create has proper return type annotation.""" + method = getattr(WebhooksClient, "create") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method delete_webhooks should have return type annotation" + ), f"Method create should have return type annotation" - def test_get_webhooks_exists(self): - """Test that get_webhooks method exists with correct signature.""" + def test_validate_exists(self): + """Test that validate method exists with correct signature.""" # Check method exists - method = getattr(WebhooksClient, "get_webhooks", None) - assert ( - method is not None - ), f"Method get_webhooks does not exist on WebhooksClient" + method = getattr(WebhooksClient, "validate", None) + assert method is not None, f"Method validate does not exist on WebhooksClient" # Check method is callable - assert callable(method), f"get_webhooks is not callable" + assert callable(method), f"validate is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert len(params) >= 1, f"get_webhooks should have at least 'self' parameter" + assert len(params) >= 1, f"validate should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [] + required_params = [ + "webhook_id", + ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from get_webhooks" + ), f"Required parameter '{required_param}' missing from validate" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -152,41 +140,39 @@ def test_get_webhooks_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_get_webhooks_return_annotation(self): - """Test that get_webhooks has proper return type annotation.""" - method = getattr(WebhooksClient, "get_webhooks") + def test_validate_return_annotation(self): + """Test that validate has proper return type annotation.""" + method = getattr(WebhooksClient, "validate") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method get_webhooks should have return type annotation" + ), f"Method validate should have return type annotation" - def test_create_webhooks_exists(self): - """Test that create_webhooks method exists with correct signature.""" + def test_delete_exists(self): + """Test that delete method exists with correct signature.""" # Check method exists - method = getattr(WebhooksClient, "create_webhooks", None) - assert ( - method is not None - ), f"Method create_webhooks does not exist on WebhooksClient" + method = getattr(WebhooksClient, "delete", None) + assert method is not None, f"Method delete does not exist on WebhooksClient" # Check method is callable - assert callable(method), f"create_webhooks is not callable" + assert callable(method), f"delete is not callable" # Check method signature sig = inspect.signature(method) params = list(sig.parameters.keys()) # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"create_webhooks should have at least 'self' parameter" + assert len(params) >= 1, f"delete should have at least 'self' parameter" assert ( params[0] == "self" ), f"First parameter should be 'self', got '{params[0]}'" # Check required parameters exist (excluding 'self') - required_params = [] + required_params = [ + "webhook_id", + ] for required_param in required_params: assert ( required_param in params - ), f"Required parameter '{required_param}' missing from create_webhooks" + ), f"Required parameter '{required_param}' missing from delete" # Check optional parameters have defaults (excluding 'self') optional_params = [] for optional_param in optional_params: @@ -197,23 +183,23 @@ def test_create_webhooks_exists(self): ), f"Optional parameter '{optional_param}' should have a default value" - def test_create_webhooks_return_annotation(self): - """Test that create_webhooks has proper return type annotation.""" - method = getattr(WebhooksClient, "create_webhooks") + def test_delete_return_annotation(self): + """Test that delete has proper return type annotation.""" + method = getattr(WebhooksClient, "delete") sig = inspect.signature(method) # Check return annotation exists assert ( sig.return_annotation is not inspect.Signature.empty - ), f"Method create_webhooks should have return type annotation" + ), f"Method delete should have return type annotation" def test_all_expected_methods_exist(self): """Test that all expected methods exist on the client.""" expected_methods = [ - "validate_webhooks", - "delete_webhooks", - "get_webhooks", - "create_webhooks", + "get", + "create", + "validate", + "delete", ] for expected_method in expected_methods: assert hasattr( diff --git a/xdk/python/uv.lock b/xdk/python/uv.lock index 0db508bc..ce03761c 100644 --- a/xdk/python/uv.lock +++ b/xdk/python/uv.lock @@ -114,89 +114,88 @@ wheels = [ [[package]] name = "charset-normalizer" -version = "3.4.2" +version = "3.4.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } +sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371, upload-time = "2025-08-09T07:57:28.46Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/28/9901804da60055b406e1a1c5ba7aac1276fb77f1dde635aabfc7fd84b8ab/charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", size = 201818, upload-time = "2025-05-02T08:31:46.725Z" }, - { url = "https://files.pythonhosted.org/packages/d9/9b/892a8c8af9110935e5adcbb06d9c6fe741b6bb02608c6513983048ba1a18/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd", size = 144649, upload-time = "2025-05-02T08:31:48.889Z" }, - { url = "https://files.pythonhosted.org/packages/7b/a5/4179abd063ff6414223575e008593861d62abfc22455b5d1a44995b7c101/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6", size = 155045, upload-time = "2025-05-02T08:31:50.757Z" }, - { url = "https://files.pythonhosted.org/packages/3b/95/bc08c7dfeddd26b4be8c8287b9bb055716f31077c8b0ea1cd09553794665/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d", size = 147356, upload-time = "2025-05-02T08:31:52.634Z" }, - { url = "https://files.pythonhosted.org/packages/a8/2d/7a5b635aa65284bf3eab7653e8b4151ab420ecbae918d3e359d1947b4d61/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86", size = 149471, upload-time = "2025-05-02T08:31:56.207Z" }, - { url = "https://files.pythonhosted.org/packages/ae/38/51fc6ac74251fd331a8cfdb7ec57beba8c23fd5493f1050f71c87ef77ed0/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c", size = 151317, upload-time = "2025-05-02T08:31:57.613Z" }, - { url = "https://files.pythonhosted.org/packages/b7/17/edee1e32215ee6e9e46c3e482645b46575a44a2d72c7dfd49e49f60ce6bf/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0", size = 146368, upload-time = "2025-05-02T08:31:59.468Z" }, - { url = "https://files.pythonhosted.org/packages/26/2c/ea3e66f2b5f21fd00b2825c94cafb8c326ea6240cd80a91eb09e4a285830/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef", size = 154491, upload-time = "2025-05-02T08:32:01.219Z" }, - { url = "https://files.pythonhosted.org/packages/52/47/7be7fa972422ad062e909fd62460d45c3ef4c141805b7078dbab15904ff7/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6", size = 157695, upload-time = "2025-05-02T08:32:03.045Z" }, - { url = "https://files.pythonhosted.org/packages/2f/42/9f02c194da282b2b340f28e5fb60762de1151387a36842a92b533685c61e/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366", size = 154849, upload-time = "2025-05-02T08:32:04.651Z" }, - { url = "https://files.pythonhosted.org/packages/67/44/89cacd6628f31fb0b63201a618049be4be2a7435a31b55b5eb1c3674547a/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db", size = 150091, upload-time = "2025-05-02T08:32:06.719Z" }, - { url = "https://files.pythonhosted.org/packages/1f/79/4b8da9f712bc079c0f16b6d67b099b0b8d808c2292c937f267d816ec5ecc/charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a", size = 98445, upload-time = "2025-05-02T08:32:08.66Z" }, - { url = "https://files.pythonhosted.org/packages/7d/d7/96970afb4fb66497a40761cdf7bd4f6fca0fc7bafde3a84f836c1f57a926/charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509", size = 105782, upload-time = "2025-05-02T08:32:10.46Z" }, - { url = "https://files.pythonhosted.org/packages/05/85/4c40d00dcc6284a1c1ad5de5e0996b06f39d8232f1031cd23c2f5c07ee86/charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2", size = 198794, upload-time = "2025-05-02T08:32:11.945Z" }, - { url = "https://files.pythonhosted.org/packages/41/d9/7a6c0b9db952598e97e93cbdfcb91bacd89b9b88c7c983250a77c008703c/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645", size = 142846, upload-time = "2025-05-02T08:32:13.946Z" }, - { url = "https://files.pythonhosted.org/packages/66/82/a37989cda2ace7e37f36c1a8ed16c58cf48965a79c2142713244bf945c89/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd", size = 153350, upload-time = "2025-05-02T08:32:15.873Z" }, - { url = "https://files.pythonhosted.org/packages/df/68/a576b31b694d07b53807269d05ec3f6f1093e9545e8607121995ba7a8313/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8", size = 145657, upload-time = "2025-05-02T08:32:17.283Z" }, - { url = "https://files.pythonhosted.org/packages/92/9b/ad67f03d74554bed3aefd56fe836e1623a50780f7c998d00ca128924a499/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f", size = 147260, upload-time = "2025-05-02T08:32:18.807Z" }, - { url = "https://files.pythonhosted.org/packages/a6/e6/8aebae25e328160b20e31a7e9929b1578bbdc7f42e66f46595a432f8539e/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7", size = 149164, upload-time = "2025-05-02T08:32:20.333Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f2/b3c2f07dbcc248805f10e67a0262c93308cfa149a4cd3d1fe01f593e5fd2/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9", size = 144571, upload-time = "2025-05-02T08:32:21.86Z" }, - { url = "https://files.pythonhosted.org/packages/60/5b/c3f3a94bc345bc211622ea59b4bed9ae63c00920e2e8f11824aa5708e8b7/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544", size = 151952, upload-time = "2025-05-02T08:32:23.434Z" }, - { url = "https://files.pythonhosted.org/packages/e2/4d/ff460c8b474122334c2fa394a3f99a04cf11c646da895f81402ae54f5c42/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82", size = 155959, upload-time = "2025-05-02T08:32:24.993Z" }, - { url = "https://files.pythonhosted.org/packages/a2/2b/b964c6a2fda88611a1fe3d4c400d39c66a42d6c169c924818c848f922415/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0", size = 153030, upload-time = "2025-05-02T08:32:26.435Z" }, - { url = "https://files.pythonhosted.org/packages/59/2e/d3b9811db26a5ebf444bc0fa4f4be5aa6d76fc6e1c0fd537b16c14e849b6/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5", size = 148015, upload-time = "2025-05-02T08:32:28.376Z" }, - { url = "https://files.pythonhosted.org/packages/90/07/c5fd7c11eafd561bb51220d600a788f1c8d77c5eef37ee49454cc5c35575/charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a", size = 98106, upload-time = "2025-05-02T08:32:30.281Z" }, - { url = "https://files.pythonhosted.org/packages/a8/05/5e33dbef7e2f773d672b6d79f10ec633d4a71cd96db6673625838a4fd532/charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28", size = 105402, upload-time = "2025-05-02T08:32:32.191Z" }, - { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, - { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, - { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, - { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, - { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, - { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, - { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, - { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, - { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, - { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, - { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, - { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, - { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, - { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, - { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, - { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, - { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, - { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, - { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, - { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, - { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, - { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, - { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, - { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, - { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, - { url = "https://files.pythonhosted.org/packages/4c/fd/f700cfd4ad876def96d2c769d8a32d808b12d1010b6003dc6639157f99ee/charset_normalizer-3.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb", size = 198257, upload-time = "2025-05-02T08:33:45.511Z" }, - { url = "https://files.pythonhosted.org/packages/3a/95/6eec4cbbbd119e6a402e3bfd16246785cc52ce64cf21af2ecdf7b3a08e91/charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a", size = 143453, upload-time = "2025-05-02T08:33:47.463Z" }, - { url = "https://files.pythonhosted.org/packages/b6/b3/d4f913660383b3d93dbe6f687a312ea9f7e89879ae883c4e8942048174d4/charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45", size = 153130, upload-time = "2025-05-02T08:33:50.568Z" }, - { url = "https://files.pythonhosted.org/packages/e5/69/7540141529eabc55bf19cc05cd9b61c2078bebfcdbd3e799af99b777fc28/charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5", size = 145688, upload-time = "2025-05-02T08:33:52.828Z" }, - { url = "https://files.pythonhosted.org/packages/2e/bb/d76d3d6e340fb0967c43c564101e28a78c9a363ea62f736a68af59ee3683/charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1", size = 147418, upload-time = "2025-05-02T08:33:54.718Z" }, - { url = "https://files.pythonhosted.org/packages/3e/ef/b7c1f39c0dc3808160c8b72e0209c2479393966313bfebc833533cfff9cc/charset_normalizer-3.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027", size = 150066, upload-time = "2025-05-02T08:33:56.597Z" }, - { url = "https://files.pythonhosted.org/packages/20/26/4e47cc23d2a4a5eb6ed7d6f0f8cda87d753e2f8abc936d5cf5ad2aae8518/charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b", size = 144499, upload-time = "2025-05-02T08:33:58.637Z" }, - { url = "https://files.pythonhosted.org/packages/d7/9c/efdf59dd46593cecad0548d36a702683a0bdc056793398a9cd1e1546ad21/charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455", size = 152954, upload-time = "2025-05-02T08:34:00.552Z" }, - { url = "https://files.pythonhosted.org/packages/59/b3/4e8b73f7299d9aaabd7cd26db4a765f741b8e57df97b034bb8de15609002/charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01", size = 155876, upload-time = "2025-05-02T08:34:02.527Z" }, - { url = "https://files.pythonhosted.org/packages/53/cb/6fa0ccf941a069adce3edb8a1e430bc80e4929f4d43b5140fdf8628bdf7d/charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58", size = 153186, upload-time = "2025-05-02T08:34:04.481Z" }, - { url = "https://files.pythonhosted.org/packages/ac/c6/80b93fabc626b75b1665ffe405e28c3cef0aae9237c5c05f15955af4edd8/charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681", size = 148007, upload-time = "2025-05-02T08:34:06.888Z" }, - { url = "https://files.pythonhosted.org/packages/41/eb/c7367ac326a2628e4f05b5c737c86fe4a8eb3ecc597a4243fc65720b3eeb/charset_normalizer-3.4.2-cp38-cp38-win32.whl", hash = "sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7", size = 97923, upload-time = "2025-05-02T08:34:08.792Z" }, - { url = "https://files.pythonhosted.org/packages/7c/02/1c82646582ccf2c757fa6af69b1a3ea88744b8d2b4ab93b7686b2533e023/charset_normalizer-3.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a", size = 105020, upload-time = "2025-05-02T08:34:10.6Z" }, - { url = "https://files.pythonhosted.org/packages/28/f8/dfb01ff6cc9af38552c69c9027501ff5a5117c4cc18dcd27cb5259fa1888/charset_normalizer-3.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4", size = 201671, upload-time = "2025-05-02T08:34:12.696Z" }, - { url = "https://files.pythonhosted.org/packages/32/fb/74e26ee556a9dbfe3bd264289b67be1e6d616329403036f6507bb9f3f29c/charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7", size = 144744, upload-time = "2025-05-02T08:34:14.665Z" }, - { url = "https://files.pythonhosted.org/packages/ad/06/8499ee5aa7addc6f6d72e068691826ff093329fe59891e83b092ae4c851c/charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836", size = 154993, upload-time = "2025-05-02T08:34:17.134Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a2/5e4c187680728219254ef107a6949c60ee0e9a916a5dadb148c7ae82459c/charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597", size = 147382, upload-time = "2025-05-02T08:34:19.081Z" }, - { url = "https://files.pythonhosted.org/packages/4c/fe/56aca740dda674f0cc1ba1418c4d84534be51f639b5f98f538b332dc9a95/charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7", size = 149536, upload-time = "2025-05-02T08:34:21.073Z" }, - { url = "https://files.pythonhosted.org/packages/53/13/db2e7779f892386b589173dd689c1b1e304621c5792046edd8a978cbf9e0/charset_normalizer-3.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f", size = 151349, upload-time = "2025-05-02T08:34:23.193Z" }, - { url = "https://files.pythonhosted.org/packages/69/35/e52ab9a276186f729bce7a0638585d2982f50402046e4b0faa5d2c3ef2da/charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba", size = 146365, upload-time = "2025-05-02T08:34:25.187Z" }, - { url = "https://files.pythonhosted.org/packages/a6/d8/af7333f732fc2e7635867d56cb7c349c28c7094910c72267586947561b4b/charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12", size = 154499, upload-time = "2025-05-02T08:34:27.359Z" }, - { url = "https://files.pythonhosted.org/packages/7a/3d/a5b2e48acef264d71e036ff30bcc49e51bde80219bb628ba3e00cf59baac/charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518", size = 157735, upload-time = "2025-05-02T08:34:29.798Z" }, - { url = "https://files.pythonhosted.org/packages/85/d8/23e2c112532a29f3eef374375a8684a4f3b8e784f62b01da931186f43494/charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5", size = 154786, upload-time = "2025-05-02T08:34:31.858Z" }, - { url = "https://files.pythonhosted.org/packages/c7/57/93e0169f08ecc20fe82d12254a200dfaceddc1c12a4077bf454ecc597e33/charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3", size = 150203, upload-time = "2025-05-02T08:34:33.88Z" }, - { url = "https://files.pythonhosted.org/packages/2c/9d/9bf2b005138e7e060d7ebdec7503d0ef3240141587651f4b445bdf7286c2/charset_normalizer-3.4.2-cp39-cp39-win32.whl", hash = "sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471", size = 98436, upload-time = "2025-05-02T08:34:35.907Z" }, - { url = "https://files.pythonhosted.org/packages/6d/24/5849d46cf4311bbf21b424c443b09b459f5b436b1558c04e45dbb7cc478b/charset_normalizer-3.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e", size = 105772, upload-time = "2025-05-02T08:34:37.935Z" }, - { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, + { url = "https://files.pythonhosted.org/packages/d6/98/f3b8013223728a99b908c9344da3aa04ee6e3fa235f19409033eda92fb78/charset_normalizer-3.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72", size = 207695, upload-time = "2025-08-09T07:55:36.452Z" }, + { url = "https://files.pythonhosted.org/packages/21/40/5188be1e3118c82dcb7c2a5ba101b783822cfb413a0268ed3be0468532de/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe", size = 147153, upload-time = "2025-08-09T07:55:38.467Z" }, + { url = "https://files.pythonhosted.org/packages/37/60/5d0d74bc1e1380f0b72c327948d9c2aca14b46a9efd87604e724260f384c/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:07a0eae9e2787b586e129fdcbe1af6997f8d0e5abaa0bc98c0e20e124d67e601", size = 160428, upload-time = "2025-08-09T07:55:40.072Z" }, + { url = "https://files.pythonhosted.org/packages/85/9a/d891f63722d9158688de58d050c59dc3da560ea7f04f4c53e769de5140f5/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:74d77e25adda8581ffc1c720f1c81ca082921329452eba58b16233ab1842141c", size = 157627, upload-time = "2025-08-09T07:55:41.706Z" }, + { url = "https://files.pythonhosted.org/packages/65/1a/7425c952944a6521a9cfa7e675343f83fd82085b8af2b1373a2409c683dc/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0e909868420b7049dafd3a31d45125b31143eec59235311fc4c57ea26a4acd2", size = 152388, upload-time = "2025-08-09T07:55:43.262Z" }, + { url = "https://files.pythonhosted.org/packages/f0/c9/a2c9c2a355a8594ce2446085e2ec97fd44d323c684ff32042e2a6b718e1d/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c6f162aabe9a91a309510d74eeb6507fab5fff92337a15acbe77753d88d9dcf0", size = 150077, upload-time = "2025-08-09T07:55:44.903Z" }, + { url = "https://files.pythonhosted.org/packages/3b/38/20a1f44e4851aa1c9105d6e7110c9d020e093dfa5836d712a5f074a12bf7/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4ca4c094de7771a98d7fbd67d9e5dbf1eb73efa4f744a730437d8a3a5cf994f0", size = 161631, upload-time = "2025-08-09T07:55:46.346Z" }, + { url = "https://files.pythonhosted.org/packages/a4/fa/384d2c0f57edad03d7bec3ebefb462090d8905b4ff5a2d2525f3bb711fac/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:02425242e96bcf29a49711b0ca9f37e451da7c70562bc10e8ed992a5a7a25cc0", size = 159210, upload-time = "2025-08-09T07:55:47.539Z" }, + { url = "https://files.pythonhosted.org/packages/33/9e/eca49d35867ca2db336b6ca27617deed4653b97ebf45dfc21311ce473c37/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:78deba4d8f9590fe4dae384aeff04082510a709957e968753ff3c48399f6f92a", size = 153739, upload-time = "2025-08-09T07:55:48.744Z" }, + { url = "https://files.pythonhosted.org/packages/2a/91/26c3036e62dfe8de8061182d33be5025e2424002125c9500faff74a6735e/charset_normalizer-3.4.3-cp310-cp310-win32.whl", hash = "sha256:d79c198e27580c8e958906f803e63cddb77653731be08851c7df0b1a14a8fc0f", size = 99825, upload-time = "2025-08-09T07:55:50.305Z" }, + { url = "https://files.pythonhosted.org/packages/e2/c6/f05db471f81af1fa01839d44ae2a8bfeec8d2a8b4590f16c4e7393afd323/charset_normalizer-3.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:c6e490913a46fa054e03699c70019ab869e990270597018cef1d8562132c2669", size = 107452, upload-time = "2025-08-09T07:55:51.461Z" }, + { url = "https://files.pythonhosted.org/packages/7f/b5/991245018615474a60965a7c9cd2b4efbaabd16d582a5547c47ee1c7730b/charset_normalizer-3.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b256ee2e749283ef3ddcff51a675ff43798d92d746d1a6e4631bf8c707d22d0b", size = 204483, upload-time = "2025-08-09T07:55:53.12Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2a/ae245c41c06299ec18262825c1569c5d3298fc920e4ddf56ab011b417efd/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13faeacfe61784e2559e690fc53fa4c5ae97c6fcedb8eb6fb8d0a15b475d2c64", size = 145520, upload-time = "2025-08-09T07:55:54.712Z" }, + { url = "https://files.pythonhosted.org/packages/3a/a4/b3b6c76e7a635748c4421d2b92c7b8f90a432f98bda5082049af37ffc8e3/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91", size = 158876, upload-time = "2025-08-09T07:55:56.024Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e6/63bb0e10f90a8243c5def74b5b105b3bbbfb3e7bb753915fe333fb0c11ea/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:585f3b2a80fbd26b048a0be90c5aae8f06605d3c92615911c3a2b03a8a3b796f", size = 156083, upload-time = "2025-08-09T07:55:57.582Z" }, + { url = "https://files.pythonhosted.org/packages/87/df/b7737ff046c974b183ea9aa111b74185ac8c3a326c6262d413bd5a1b8c69/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e78314bdc32fa80696f72fa16dc61168fda4d6a0c014e0380f9d02f0e5d8a07", size = 150295, upload-time = "2025-08-09T07:55:59.147Z" }, + { url = "https://files.pythonhosted.org/packages/61/f1/190d9977e0084d3f1dc169acd060d479bbbc71b90bf3e7bf7b9927dec3eb/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:96b2b3d1a83ad55310de8c7b4a2d04d9277d5591f40761274856635acc5fcb30", size = 148379, upload-time = "2025-08-09T07:56:00.364Z" }, + { url = "https://files.pythonhosted.org/packages/4c/92/27dbe365d34c68cfe0ca76f1edd70e8705d82b378cb54ebbaeabc2e3029d/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:939578d9d8fd4299220161fdd76e86c6a251987476f5243e8864a7844476ba14", size = 160018, upload-time = "2025-08-09T07:56:01.678Z" }, + { url = "https://files.pythonhosted.org/packages/99/04/baae2a1ea1893a01635d475b9261c889a18fd48393634b6270827869fa34/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fd10de089bcdcd1be95a2f73dbe6254798ec1bda9f450d5828c96f93e2536b9c", size = 157430, upload-time = "2025-08-09T07:56:02.87Z" }, + { url = "https://files.pythonhosted.org/packages/2f/36/77da9c6a328c54d17b960c89eccacfab8271fdaaa228305330915b88afa9/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e8ac75d72fa3775e0b7cb7e4629cec13b7514d928d15ef8ea06bca03ef01cae", size = 151600, upload-time = "2025-08-09T07:56:04.089Z" }, + { url = "https://files.pythonhosted.org/packages/64/d4/9eb4ff2c167edbbf08cdd28e19078bf195762e9bd63371689cab5ecd3d0d/charset_normalizer-3.4.3-cp311-cp311-win32.whl", hash = "sha256:6cf8fd4c04756b6b60146d98cd8a77d0cdae0e1ca20329da2ac85eed779b6849", size = 99616, upload-time = "2025-08-09T07:56:05.658Z" }, + { url = "https://files.pythonhosted.org/packages/f4/9c/996a4a028222e7761a96634d1820de8a744ff4327a00ada9c8942033089b/charset_normalizer-3.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:31a9a6f775f9bcd865d88ee350f0ffb0e25936a7f930ca98995c05abf1faf21c", size = 107108, upload-time = "2025-08-09T07:56:07.176Z" }, + { url = "https://files.pythonhosted.org/packages/e9/5e/14c94999e418d9b87682734589404a25854d5f5d0408df68bc15b6ff54bb/charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1", size = 205655, upload-time = "2025-08-09T07:56:08.475Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a8/c6ec5d389672521f644505a257f50544c074cf5fc292d5390331cd6fc9c3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884", size = 146223, upload-time = "2025-08-09T07:56:09.708Z" }, + { url = "https://files.pythonhosted.org/packages/fc/eb/a2ffb08547f4e1e5415fb69eb7db25932c52a52bed371429648db4d84fb1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018", size = 159366, upload-time = "2025-08-09T07:56:11.326Z" }, + { url = "https://files.pythonhosted.org/packages/82/10/0fd19f20c624b278dddaf83b8464dcddc2456cb4b02bb902a6da126b87a1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392", size = 157104, upload-time = "2025-08-09T07:56:13.014Z" }, + { url = "https://files.pythonhosted.org/packages/16/ab/0233c3231af734f5dfcf0844aa9582d5a1466c985bbed6cedab85af9bfe3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f", size = 151830, upload-time = "2025-08-09T07:56:14.428Z" }, + { url = "https://files.pythonhosted.org/packages/ae/02/e29e22b4e02839a0e4a06557b1999d0a47db3567e82989b5bb21f3fbbd9f/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154", size = 148854, upload-time = "2025-08-09T07:56:16.051Z" }, + { url = "https://files.pythonhosted.org/packages/05/6b/e2539a0a4be302b481e8cafb5af8792da8093b486885a1ae4d15d452bcec/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491", size = 160670, upload-time = "2025-08-09T07:56:17.314Z" }, + { url = "https://files.pythonhosted.org/packages/31/e7/883ee5676a2ef217a40ce0bffcc3d0dfbf9e64cbcfbdf822c52981c3304b/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93", size = 158501, upload-time = "2025-08-09T07:56:18.641Z" }, + { url = "https://files.pythonhosted.org/packages/c1/35/6525b21aa0db614cf8b5792d232021dca3df7f90a1944db934efa5d20bb1/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f", size = 153173, upload-time = "2025-08-09T07:56:20.289Z" }, + { url = "https://files.pythonhosted.org/packages/50/ee/f4704bad8201de513fdc8aac1cabc87e38c5818c93857140e06e772b5892/charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37", size = 99822, upload-time = "2025-08-09T07:56:21.551Z" }, + { url = "https://files.pythonhosted.org/packages/39/f5/3b3836ca6064d0992c58c7561c6b6eee1b3892e9665d650c803bd5614522/charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc", size = 107543, upload-time = "2025-08-09T07:56:23.115Z" }, + { url = "https://files.pythonhosted.org/packages/65/ca/2135ac97709b400c7654b4b764daf5c5567c2da45a30cdd20f9eefe2d658/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe", size = 205326, upload-time = "2025-08-09T07:56:24.721Z" }, + { url = "https://files.pythonhosted.org/packages/71/11/98a04c3c97dd34e49c7d247083af03645ca3730809a5509443f3c37f7c99/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8", size = 146008, upload-time = "2025-08-09T07:56:26.004Z" }, + { url = "https://files.pythonhosted.org/packages/60/f5/4659a4cb3c4ec146bec80c32d8bb16033752574c20b1252ee842a95d1a1e/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9", size = 159196, upload-time = "2025-08-09T07:56:27.25Z" }, + { url = "https://files.pythonhosted.org/packages/86/9e/f552f7a00611f168b9a5865a1414179b2c6de8235a4fa40189f6f79a1753/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31", size = 156819, upload-time = "2025-08-09T07:56:28.515Z" }, + { url = "https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f", size = 151350, upload-time = "2025-08-09T07:56:29.716Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a9/3865b02c56f300a6f94fc631ef54f0a8a29da74fb45a773dfd3dcd380af7/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927", size = 148644, upload-time = "2025-08-09T07:56:30.984Z" }, + { url = "https://files.pythonhosted.org/packages/77/d9/cbcf1a2a5c7d7856f11e7ac2d782aec12bdfea60d104e60e0aa1c97849dc/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9", size = 160468, upload-time = "2025-08-09T07:56:32.252Z" }, + { url = "https://files.pythonhosted.org/packages/f6/42/6f45efee8697b89fda4d50580f292b8f7f9306cb2971d4b53f8914e4d890/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5", size = 158187, upload-time = "2025-08-09T07:56:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", size = 152699, upload-time = "2025-08-09T07:56:34.739Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", size = 99580, upload-time = "2025-08-09T07:56:35.981Z" }, + { url = "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", size = 107366, upload-time = "2025-08-09T07:56:37.339Z" }, + { url = "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", size = 204342, upload-time = "2025-08-09T07:56:38.687Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", size = 145995, upload-time = "2025-08-09T07:56:40.048Z" }, + { url = "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", size = 158640, upload-time = "2025-08-09T07:56:41.311Z" }, + { url = "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", size = 156636, upload-time = "2025-08-09T07:56:43.195Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", size = 150939, upload-time = "2025-08-09T07:56:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", size = 148580, upload-time = "2025-08-09T07:56:46.684Z" }, + { url = "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", size = 159870, upload-time = "2025-08-09T07:56:47.941Z" }, + { url = "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", size = 157797, upload-time = "2025-08-09T07:56:49.756Z" }, + { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" }, + { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" }, + { url = "https://files.pythonhosted.org/packages/22/82/63a45bfc36f73efe46731a3a71cb84e2112f7e0b049507025ce477f0f052/charset_normalizer-3.4.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0f2be7e0cf7754b9a30eb01f4295cc3d4358a479843b31f328afd210e2c7598c", size = 198805, upload-time = "2025-08-09T07:56:56.496Z" }, + { url = "https://files.pythonhosted.org/packages/0c/52/8b0c6c3e53f7e546a5e49b9edb876f379725914e1130297f3b423c7b71c5/charset_normalizer-3.4.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c60e092517a73c632ec38e290eba714e9627abe9d301c8c8a12ec32c314a2a4b", size = 142862, upload-time = "2025-08-09T07:56:57.751Z" }, + { url = "https://files.pythonhosted.org/packages/59/c0/a74f3bd167d311365e7973990243f32c35e7a94e45103125275b9e6c479f/charset_normalizer-3.4.3-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:252098c8c7a873e17dd696ed98bbe91dbacd571da4b87df3736768efa7a792e4", size = 155104, upload-time = "2025-08-09T07:56:58.984Z" }, + { url = "https://files.pythonhosted.org/packages/1a/79/ae516e678d6e32df2e7e740a7be51dc80b700e2697cb70054a0f1ac2c955/charset_normalizer-3.4.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3653fad4fe3ed447a596ae8638b437f827234f01a8cd801842e43f3d0a6b281b", size = 152598, upload-time = "2025-08-09T07:57:00.201Z" }, + { url = "https://files.pythonhosted.org/packages/00/bd/ef9c88464b126fa176f4ef4a317ad9b6f4d30b2cffbc43386062367c3e2c/charset_normalizer-3.4.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8999f965f922ae054125286faf9f11bc6932184b93011d138925a1773830bbe9", size = 147391, upload-time = "2025-08-09T07:57:01.441Z" }, + { url = "https://files.pythonhosted.org/packages/7a/03/cbb6fac9d3e57f7e07ce062712ee80d80a5ab46614684078461917426279/charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d95bfb53c211b57198bb91c46dd5a2d8018b3af446583aab40074bf7988401cb", size = 145037, upload-time = "2025-08-09T07:57:02.638Z" }, + { url = "https://files.pythonhosted.org/packages/64/d1/f9d141c893ef5d4243bc75c130e95af8fd4bc355beff06e9b1e941daad6e/charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:5b413b0b1bfd94dbf4023ad6945889f374cd24e3f62de58d6bb102c4d9ae534a", size = 156425, upload-time = "2025-08-09T07:57:03.898Z" }, + { url = "https://files.pythonhosted.org/packages/c5/35/9c99739250742375167bc1b1319cd1cec2bf67438a70d84b2e1ec4c9daa3/charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:b5e3b2d152e74e100a9e9573837aba24aab611d39428ded46f4e4022ea7d1942", size = 153734, upload-time = "2025-08-09T07:57:05.549Z" }, + { url = "https://files.pythonhosted.org/packages/50/10/c117806094d2c956ba88958dab680574019abc0c02bcf57b32287afca544/charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a2d08ac246bb48479170408d6c19f6385fa743e7157d716e144cad849b2dd94b", size = 148551, upload-time = "2025-08-09T07:57:06.823Z" }, + { url = "https://files.pythonhosted.org/packages/61/c5/dc3ba772489c453621ffc27e8978a98fe7e41a93e787e5e5bde797f1dddb/charset_normalizer-3.4.3-cp38-cp38-win32.whl", hash = "sha256:ec557499516fc90fd374bf2e32349a2887a876fbf162c160e3c01b6849eaf557", size = 98459, upload-time = "2025-08-09T07:57:08.031Z" }, + { url = "https://files.pythonhosted.org/packages/05/35/bb59b1cd012d7196fc81c2f5879113971efc226a63812c9cf7f89fe97c40/charset_normalizer-3.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:5d8d01eac18c423815ed4f4a2ec3b439d654e55ee4ad610e153cf02faf67ea40", size = 105887, upload-time = "2025-08-09T07:57:09.401Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ca/9a0983dd5c8e9733565cf3db4df2b0a2e9a82659fd8aa2a868ac6e4a991f/charset_normalizer-3.4.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:70bfc5f2c318afece2f5838ea5e4c3febada0be750fcf4775641052bbba14d05", size = 207520, upload-time = "2025-08-09T07:57:11.026Z" }, + { url = "https://files.pythonhosted.org/packages/39/c6/99271dc37243a4f925b09090493fb96c9333d7992c6187f5cfe5312008d2/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23b6b24d74478dc833444cbd927c338349d6ae852ba53a0d02a2de1fce45b96e", size = 147307, upload-time = "2025-08-09T07:57:12.4Z" }, + { url = "https://files.pythonhosted.org/packages/e4/69/132eab043356bba06eb333cc2cc60c6340857d0a2e4ca6dc2b51312886b3/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:34a7f768e3f985abdb42841e20e17b330ad3aaf4bb7e7aeeb73db2e70f077b99", size = 160448, upload-time = "2025-08-09T07:57:13.712Z" }, + { url = "https://files.pythonhosted.org/packages/04/9a/914d294daa4809c57667b77470533e65def9c0be1ef8b4c1183a99170e9d/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb731e5deb0c7ef82d698b0f4c5bb724633ee2a489401594c5c88b02e6cb15f7", size = 157758, upload-time = "2025-08-09T07:57:14.979Z" }, + { url = "https://files.pythonhosted.org/packages/b0/a8/6f5bcf1bcf63cb45625f7c5cadca026121ff8a6c8a3256d8d8cd59302663/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:257f26fed7d7ff59921b78244f3cd93ed2af1800ff048c33f624c87475819dd7", size = 152487, upload-time = "2025-08-09T07:57:16.332Z" }, + { url = "https://files.pythonhosted.org/packages/c4/72/d3d0e9592f4e504f9dea08b8db270821c909558c353dc3b457ed2509f2fb/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1ef99f0456d3d46a50945c98de1774da86f8e992ab5c77865ea8b8195341fc19", size = 150054, upload-time = "2025-08-09T07:57:17.576Z" }, + { url = "https://files.pythonhosted.org/packages/20/30/5f64fe3981677fe63fa987b80e6c01042eb5ff653ff7cec1b7bd9268e54e/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2c322db9c8c89009a990ef07c3bcc9f011a3269bc06782f916cd3d9eed7c9312", size = 161703, upload-time = "2025-08-09T07:57:20.012Z" }, + { url = "https://files.pythonhosted.org/packages/e1/ef/dd08b2cac9284fd59e70f7d97382c33a3d0a926e45b15fc21b3308324ffd/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:511729f456829ef86ac41ca78c63a5cb55240ed23b4b737faca0eb1abb1c41bc", size = 159096, upload-time = "2025-08-09T07:57:21.329Z" }, + { url = "https://files.pythonhosted.org/packages/45/8c/dcef87cfc2b3f002a6478f38906f9040302c68aebe21468090e39cde1445/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:88ab34806dea0671532d3f82d82b85e8fc23d7b2dd12fa837978dad9bb392a34", size = 153852, upload-time = "2025-08-09T07:57:22.608Z" }, + { url = "https://files.pythonhosted.org/packages/63/86/9cbd533bd37883d467fcd1bd491b3547a3532d0fbb46de2b99feeebf185e/charset_normalizer-3.4.3-cp39-cp39-win32.whl", hash = "sha256:16a8770207946ac75703458e2c743631c79c59c5890c80011d536248f8eaa432", size = 99840, upload-time = "2025-08-09T07:57:23.883Z" }, + { url = "https://files.pythonhosted.org/packages/ce/d6/7e805c8e5c46ff9729c49950acc4ee0aeb55efb8b3a56687658ad10c3216/charset_normalizer-3.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:d22dbedd33326a4a5190dd4fe9e9e693ef12160c77382d9e87919bce54f3d4ca", size = 107438, upload-time = "2025-08-09T07:57:25.287Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, ] [[package]] @@ -328,101 +327,101 @@ toml = [ [[package]] name = "coverage" -version = "7.10.2" +version = "7.10.3" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.10'", "python_full_version == '3.9.*'", ] -sdist = { url = "https://files.pythonhosted.org/packages/ee/76/17780846fc7aade1e66712e1e27dd28faa0a5d987a1f433610974959eaa8/coverage-7.10.2.tar.gz", hash = "sha256:5d6e6d84e6dd31a8ded64759626627247d676a23c1b892e1326f7c55c8d61055", size = 820754, upload-time = "2025-08-04T00:35:17.511Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f4/2c/253cc41cd0f40b84c1c34c5363e0407d73d4a1cae005fed6db3b823175bd/coverage-7.10.3.tar.gz", hash = "sha256:812ba9250532e4a823b070b0420a36499859542335af3dca8f47fc6aa1a05619", size = 822936, upload-time = "2025-08-10T21:27:39.968Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/5f/5ce748ab3f142593698aff5f8a0cf020775aa4e24b9d8748b5a56b64d3f8/coverage-7.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:79f0283ab5e6499fd5fe382ca3d62afa40fb50ff227676a3125d18af70eabf65", size = 215003, upload-time = "2025-08-04T00:33:02.977Z" }, - { url = "https://files.pythonhosted.org/packages/f4/ed/507088561217b000109552139802fa99c33c16ad19999c687b601b3790d0/coverage-7.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4545e906f595ee8ab8e03e21be20d899bfc06647925bc5b224ad7e8c40e08b8", size = 215391, upload-time = "2025-08-04T00:33:05.645Z" }, - { url = "https://files.pythonhosted.org/packages/79/1b/0f496259fe137c4c5e1e8eaff496fb95af88b71700f5e57725a4ddbe742b/coverage-7.10.2-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ae385e1d58fbc6a9b1c315e5510ac52281e271478b45f92ca9b5ad42cf39643f", size = 242367, upload-time = "2025-08-04T00:33:07.189Z" }, - { url = "https://files.pythonhosted.org/packages/b9/8e/5a8835fb0122a2e2a108bf3527931693c4625fdc4d953950a480b9625852/coverage-7.10.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6f0cbe5f7dd19f3a32bac2251b95d51c3b89621ac88a2648096ce40f9a5aa1e7", size = 243627, upload-time = "2025-08-04T00:33:08.809Z" }, - { url = "https://files.pythonhosted.org/packages/c3/96/6a528429c2e0e8d85261764d0cd42e51a429510509bcc14676ee5d1bb212/coverage-7.10.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fd17f427f041f6b116dc90b4049c6f3e1230524407d00daa2d8c7915037b5947", size = 245485, upload-time = "2025-08-04T00:33:10.29Z" }, - { url = "https://files.pythonhosted.org/packages/bf/82/1fba935c4d02c33275aca319deabf1f22c0f95f2c0000bf7c5f276d6f7b4/coverage-7.10.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7f10ca4cde7b466405cce0a0e9971a13eb22e57a5ecc8b5f93a81090cc9c7eb9", size = 243429, upload-time = "2025-08-04T00:33:11.909Z" }, - { url = "https://files.pythonhosted.org/packages/fc/a8/c8dc0a57a729fc93be33ab78f187a8f52d455fa8f79bfb379fe23b45868d/coverage-7.10.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3b990df23dd51dccce26d18fb09fd85a77ebe46368f387b0ffba7a74e470b31b", size = 242104, upload-time = "2025-08-04T00:33:13.467Z" }, - { url = "https://files.pythonhosted.org/packages/b9/6f/0b7da1682e2557caeed299a00897b42afde99a241a01eba0197eb982b90f/coverage-7.10.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc3902584d25c7eef57fb38f440aa849a26a3a9f761a029a72b69acfca4e31f8", size = 242397, upload-time = "2025-08-04T00:33:14.682Z" }, - { url = "https://files.pythonhosted.org/packages/2d/e4/54dc833dadccd519c04a28852f39a37e522bad35d70cfe038817cdb8f168/coverage-7.10.2-cp310-cp310-win32.whl", hash = "sha256:9dd37e9ac00d5eb72f38ed93e3cdf2280b1dbda3bb9b48c6941805f265ad8d87", size = 217502, upload-time = "2025-08-04T00:33:16.254Z" }, - { url = "https://files.pythonhosted.org/packages/c3/e7/2f78159c4c127549172f427dff15b02176329327bf6a6a1fcf1f603b5456/coverage-7.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:99d16f15cb5baf0729354c5bd3080ae53847a4072b9ba1e10957522fb290417f", size = 218388, upload-time = "2025-08-04T00:33:17.4Z" }, - { url = "https://files.pythonhosted.org/packages/6e/53/0125a6fc0af4f2687b4e08b0fb332cd0d5e60f3ca849e7456f995d022656/coverage-7.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c3b210d79925a476dfc8d74c7d53224888421edebf3a611f3adae923e212b27", size = 215119, upload-time = "2025-08-04T00:33:19.101Z" }, - { url = "https://files.pythonhosted.org/packages/0e/2e/960d9871de9152dbc9ff950913c6a6e9cf2eb4cc80d5bc8f93029f9f2f9f/coverage-7.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf67d1787cd317c3f8b2e4c6ed1ae93497be7e30605a0d32237ac37a37a8a322", size = 215511, upload-time = "2025-08-04T00:33:20.32Z" }, - { url = "https://files.pythonhosted.org/packages/3f/34/68509e44995b9cad806d81b76c22bc5181f3535bca7cd9c15791bfd8951e/coverage-7.10.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:069b779d03d458602bc0e27189876e7d8bdf6b24ac0f12900de22dd2154e6ad7", size = 245513, upload-time = "2025-08-04T00:33:21.896Z" }, - { url = "https://files.pythonhosted.org/packages/ef/d4/9b12f357413248ce40804b0f58030b55a25b28a5c02db95fb0aa50c5d62c/coverage-7.10.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4c2de4cb80b9990e71c62c2d3e9f3ec71b804b1f9ca4784ec7e74127e0f42468", size = 247350, upload-time = "2025-08-04T00:33:23.917Z" }, - { url = "https://files.pythonhosted.org/packages/b6/40/257945eda1f72098e4a3c350b1d68fdc5d7d032684a0aeb6c2391153ecf4/coverage-7.10.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75bf7ab2374a7eb107602f1e07310cda164016cd60968abf817b7a0b5703e288", size = 249516, upload-time = "2025-08-04T00:33:25.5Z" }, - { url = "https://files.pythonhosted.org/packages/ff/55/8987f852ece378cecbf39a367f3f7ec53351e39a9151b130af3a3045b83f/coverage-7.10.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3f37516458ec1550815134937f73d6d15b434059cd10f64678a2068f65c62406", size = 247241, upload-time = "2025-08-04T00:33:26.767Z" }, - { url = "https://files.pythonhosted.org/packages/df/ae/da397de7a42a18cea6062ed9c3b72c50b39e0b9e7b2893d7172d3333a9a1/coverage-7.10.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:de3c6271c482c250d3303fb5c6bdb8ca025fff20a67245e1425df04dc990ece9", size = 245274, upload-time = "2025-08-04T00:33:28.494Z" }, - { url = "https://files.pythonhosted.org/packages/4e/64/7baa895eb55ec0e1ec35b988687ecd5d4475ababb0d7ae5ca3874dd90ee7/coverage-7.10.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:98a838101321ac3089c9bb1d4bfa967e8afed58021fda72d7880dc1997f20ae1", size = 245882, upload-time = "2025-08-04T00:33:30.048Z" }, - { url = "https://files.pythonhosted.org/packages/24/6c/1fd76a0bd09ae75220ae9775a8290416d726f0e5ba26ea72346747161240/coverage-7.10.2-cp311-cp311-win32.whl", hash = "sha256:f2a79145a531a0e42df32d37be5af069b4a914845b6f686590739b786f2f7bce", size = 217541, upload-time = "2025-08-04T00:33:31.376Z" }, - { url = "https://files.pythonhosted.org/packages/5f/2d/8c18fb7a6e74c79fd4661e82535bc8c68aee12f46c204eabf910b097ccc9/coverage-7.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:e4f5f1320f8ee0d7cfa421ceb257bef9d39fd614dd3ddcfcacd284d4824ed2c2", size = 218426, upload-time = "2025-08-04T00:33:32.976Z" }, - { url = "https://files.pythonhosted.org/packages/da/40/425bb35e4ff7c7af177edf5dffd4154bc2a677b27696afe6526d75c77fec/coverage-7.10.2-cp311-cp311-win_arm64.whl", hash = "sha256:d8f2d83118f25328552c728b8e91babf93217db259ca5c2cd4dd4220b8926293", size = 217116, upload-time = "2025-08-04T00:33:34.302Z" }, - { url = "https://files.pythonhosted.org/packages/4e/1e/2c752bdbbf6f1199c59b1a10557fbb6fb3dc96b3c0077b30bd41a5922c1f/coverage-7.10.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:890ad3a26da9ec7bf69255b9371800e2a8da9bc223ae5d86daeb940b42247c83", size = 215311, upload-time = "2025-08-04T00:33:35.524Z" }, - { url = "https://files.pythonhosted.org/packages/68/6a/84277d73a2cafb96e24be81b7169372ba7ff28768ebbf98e55c85a491b0f/coverage-7.10.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38fd1ccfca7838c031d7a7874d4353e2f1b98eb5d2a80a2fe5732d542ae25e9c", size = 215550, upload-time = "2025-08-04T00:33:37.109Z" }, - { url = "https://files.pythonhosted.org/packages/b5/e7/5358b73b46ac76f56cc2de921eeabd44fabd0b7ff82ea4f6b8c159c4d5dc/coverage-7.10.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:76c1ffaaf4f6f0f6e8e9ca06f24bb6454a7a5d4ced97a1bc466f0d6baf4bd518", size = 246564, upload-time = "2025-08-04T00:33:38.33Z" }, - { url = "https://files.pythonhosted.org/packages/7c/0e/b0c901dd411cb7fc0cfcb28ef0dc6f3049030f616bfe9fc4143aecd95901/coverage-7.10.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:86da8a3a84b79ead5c7d0e960c34f580bc3b231bb546627773a3f53c532c2f21", size = 248993, upload-time = "2025-08-04T00:33:39.555Z" }, - { url = "https://files.pythonhosted.org/packages/0e/4e/a876db272072a9e0df93f311e187ccdd5f39a190c6d1c1f0b6e255a0d08e/coverage-7.10.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99cef9731c8a39801830a604cc53c93c9e57ea8b44953d26589499eded9576e0", size = 250454, upload-time = "2025-08-04T00:33:41.023Z" }, - { url = "https://files.pythonhosted.org/packages/64/d6/1222dc69f8dd1be208d55708a9f4a450ad582bf4fa05320617fea1eaa6d8/coverage-7.10.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ea58b112f2966a8b91eb13f5d3b1f8bb43c180d624cd3283fb33b1cedcc2dd75", size = 248365, upload-time = "2025-08-04T00:33:42.376Z" }, - { url = "https://files.pythonhosted.org/packages/62/e3/40fd71151064fc315c922dd9a35e15b30616f00146db1d6a0b590553a75a/coverage-7.10.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:20f405188d28da9522b7232e51154e1b884fc18d0b3a10f382d54784715bbe01", size = 246562, upload-time = "2025-08-04T00:33:43.663Z" }, - { url = "https://files.pythonhosted.org/packages/fc/14/8aa93ddcd6623ddaef5d8966268ac9545b145bce4fe7b1738fd1c3f0d957/coverage-7.10.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:64586ce42bbe0da4d9f76f97235c545d1abb9b25985a8791857690f96e23dc3b", size = 247772, upload-time = "2025-08-04T00:33:45.068Z" }, - { url = "https://files.pythonhosted.org/packages/07/4e/dcb1c01490623c61e2f2ea85cb185fa6a524265bb70eeb897d3c193efeb9/coverage-7.10.2-cp312-cp312-win32.whl", hash = "sha256:bc2e69b795d97ee6d126e7e22e78a509438b46be6ff44f4dccbb5230f550d340", size = 217710, upload-time = "2025-08-04T00:33:46.378Z" }, - { url = "https://files.pythonhosted.org/packages/79/16/e8aab4162b5f80ad2e5e1f54b1826e2053aa2f4db508b864af647f00c239/coverage-7.10.2-cp312-cp312-win_amd64.whl", hash = "sha256:adda2268b8cf0d11f160fad3743b4dfe9813cd6ecf02c1d6397eceaa5b45b388", size = 218499, upload-time = "2025-08-04T00:33:48.048Z" }, - { url = "https://files.pythonhosted.org/packages/06/7f/c112ec766e8f1131ce8ce26254be028772757b2d1e63e4f6a4b0ad9a526c/coverage-7.10.2-cp312-cp312-win_arm64.whl", hash = "sha256:164429decd0d6b39a0582eaa30c67bf482612c0330572343042d0ed9e7f15c20", size = 217154, upload-time = "2025-08-04T00:33:49.299Z" }, - { url = "https://files.pythonhosted.org/packages/8d/04/9b7a741557f93c0ed791b854d27aa8d9fe0b0ce7bb7c52ca1b0f2619cb74/coverage-7.10.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:aca7b5645afa688de6d4f8e89d30c577f62956fefb1bad021490d63173874186", size = 215337, upload-time = "2025-08-04T00:33:50.61Z" }, - { url = "https://files.pythonhosted.org/packages/02/a4/8d1088cd644750c94bc305d3cf56082b4cdf7fb854a25abb23359e74892f/coverage-7.10.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:96e5921342574a14303dfdb73de0019e1ac041c863743c8fe1aa6c2b4a257226", size = 215596, upload-time = "2025-08-04T00:33:52.33Z" }, - { url = "https://files.pythonhosted.org/packages/01/2f/643a8d73343f70e162d8177a3972b76e306b96239026bc0c12cfde4f7c7a/coverage-7.10.2-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:11333094c1bff621aa811b67ed794865cbcaa99984dedea4bd9cf780ad64ecba", size = 246145, upload-time = "2025-08-04T00:33:53.641Z" }, - { url = "https://files.pythonhosted.org/packages/1f/4a/722098d1848db4072cda71b69ede1e55730d9063bf868375264d0d302bc9/coverage-7.10.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6eb586fa7d2aee8d65d5ae1dd71414020b2f447435c57ee8de8abea0a77d5074", size = 248492, upload-time = "2025-08-04T00:33:55.366Z" }, - { url = "https://files.pythonhosted.org/packages/3f/b0/8a6d7f326f6e3e6ed398cde27f9055e860a1e858317001835c521673fb60/coverage-7.10.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2d358f259d8019d4ef25d8c5b78aca4c7af25e28bd4231312911c22a0e824a57", size = 249927, upload-time = "2025-08-04T00:33:57.042Z" }, - { url = "https://files.pythonhosted.org/packages/bb/21/1aaadd3197b54d1e61794475379ecd0f68d8fc5c2ebd352964dc6f698a3d/coverage-7.10.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5250bda76e30382e0a2dcd68d961afcab92c3a7613606e6269855c6979a1b0bb", size = 248138, upload-time = "2025-08-04T00:33:58.329Z" }, - { url = "https://files.pythonhosted.org/packages/48/65/be75bafb2bdd22fd8bf9bf63cd5873b91bb26ec0d68f02d4b8b09c02decb/coverage-7.10.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a91e027d66eff214d88d9afbe528e21c9ef1ecdf4956c46e366c50f3094696d0", size = 246111, upload-time = "2025-08-04T00:33:59.899Z" }, - { url = "https://files.pythonhosted.org/packages/5e/30/a4f0c5e249c3cc60e6c6f30d8368e372f2d380eda40e0434c192ac27ccf5/coverage-7.10.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:228946da741558904e2c03ce870ba5efd9cd6e48cbc004d9a27abee08100a15a", size = 247493, upload-time = "2025-08-04T00:34:01.619Z" }, - { url = "https://files.pythonhosted.org/packages/85/99/f09b9493e44a75cf99ca834394c12f8cb70da6c1711ee296534f97b52729/coverage-7.10.2-cp313-cp313-win32.whl", hash = "sha256:95e23987b52d02e7c413bf2d6dc6288bd5721beb518052109a13bfdc62c8033b", size = 217756, upload-time = "2025-08-04T00:34:03.277Z" }, - { url = "https://files.pythonhosted.org/packages/2d/bb/cbcb09103be330c7d26ff0ab05c4a8861dd2e254656fdbd3eb7600af4336/coverage-7.10.2-cp313-cp313-win_amd64.whl", hash = "sha256:f35481d42c6d146d48ec92d4e239c23f97b53a3f1fbd2302e7c64336f28641fe", size = 218526, upload-time = "2025-08-04T00:34:04.635Z" }, - { url = "https://files.pythonhosted.org/packages/37/8f/8bfb4e0bca52c00ab680767c0dd8cfd928a2a72d69897d9b2d5d8b5f63f5/coverage-7.10.2-cp313-cp313-win_arm64.whl", hash = "sha256:65b451949cb789c346f9f9002441fc934d8ccedcc9ec09daabc2139ad13853f7", size = 217176, upload-time = "2025-08-04T00:34:05.973Z" }, - { url = "https://files.pythonhosted.org/packages/1e/25/d458ba0bf16a8204a88d74dbb7ec5520f29937ffcbbc12371f931c11efd2/coverage-7.10.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:e8415918856a3e7d57a4e0ad94651b761317de459eb74d34cc1bb51aad80f07e", size = 216058, upload-time = "2025-08-04T00:34:07.368Z" }, - { url = "https://files.pythonhosted.org/packages/0b/1c/af4dfd2d7244dc7610fed6d59d57a23ea165681cd764445dc58d71ed01a6/coverage-7.10.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f287a25a8ca53901c613498e4a40885b19361a2fe8fbfdbb7f8ef2cad2a23f03", size = 216273, upload-time = "2025-08-04T00:34:09.073Z" }, - { url = "https://files.pythonhosted.org/packages/8e/67/ec5095d4035c6e16368226fa9cb15f77f891194c7e3725aeefd08e7a3e5a/coverage-7.10.2-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:75cc1a3f8c88c69bf16a871dab1fe5a7303fdb1e9f285f204b60f1ee539b8fc0", size = 257513, upload-time = "2025-08-04T00:34:10.403Z" }, - { url = "https://files.pythonhosted.org/packages/1c/47/be5550b57a3a8ba797de4236b0fd31031f88397b2afc84ab3c2d4cf265f6/coverage-7.10.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ca07fa78cc9d26bc8c4740de1abd3489cf9c47cc06d9a8ab3d552ff5101af4c0", size = 259377, upload-time = "2025-08-04T00:34:12.138Z" }, - { url = "https://files.pythonhosted.org/packages/37/50/b12a4da1382e672305c2d17cd3029dc16b8a0470de2191dbf26b91431378/coverage-7.10.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c2e117e64c26300032755d4520cd769f2623cde1a1d1c3515b05a3b8add0ade1", size = 261516, upload-time = "2025-08-04T00:34:13.608Z" }, - { url = "https://files.pythonhosted.org/packages/db/41/4d3296dbd33dd8da178171540ca3391af7c0184c0870fd4d4574ac290290/coverage-7.10.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:daaf98009977f577b71f8800208f4d40d4dcf5c2db53d4d822787cdc198d76e1", size = 259110, upload-time = "2025-08-04T00:34:15.089Z" }, - { url = "https://files.pythonhosted.org/packages/ea/f1/b409959ecbc0cec0e61e65683b22bacaa4a3b11512f834e16dd8ffbc37db/coverage-7.10.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ea8d8fe546c528535c761ba424410bbeb36ba8a0f24be653e94b70c93fd8a8ca", size = 257248, upload-time = "2025-08-04T00:34:16.501Z" }, - { url = "https://files.pythonhosted.org/packages/48/ab/7076dc1c240412e9267d36ec93e9e299d7659f6a5c1e958f87e998b0fb6d/coverage-7.10.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:fe024d40ac31eb8d5aae70215b41dafa264676caa4404ae155f77d2fa95c37bb", size = 258063, upload-time = "2025-08-04T00:34:18.338Z" }, - { url = "https://files.pythonhosted.org/packages/1e/77/f6b51a0288f8f5f7dcc7c89abdd22cf514f3bc5151284f5cd628917f8e10/coverage-7.10.2-cp313-cp313t-win32.whl", hash = "sha256:8f34b09f68bdadec122ffad312154eda965ade433559cc1eadd96cca3de5c824", size = 218433, upload-time = "2025-08-04T00:34:19.71Z" }, - { url = "https://files.pythonhosted.org/packages/7b/6d/547a86493e25270ce8481543e77f3a0aa3aa872c1374246b7b76273d66eb/coverage-7.10.2-cp313-cp313t-win_amd64.whl", hash = "sha256:71d40b3ac0f26fa9ffa6ee16219a714fed5c6ec197cdcd2018904ab5e75bcfa3", size = 219523, upload-time = "2025-08-04T00:34:21.171Z" }, - { url = "https://files.pythonhosted.org/packages/ff/d5/3c711e38eaf9ab587edc9bed232c0298aed84e751a9f54aaa556ceaf7da6/coverage-7.10.2-cp313-cp313t-win_arm64.whl", hash = "sha256:abb57fdd38bf6f7dcc66b38dafb7af7c5fdc31ac6029ce373a6f7f5331d6f60f", size = 217739, upload-time = "2025-08-04T00:34:22.514Z" }, - { url = "https://files.pythonhosted.org/packages/71/53/83bafa669bb9d06d4c8c6a055d8d05677216f9480c4698fb183ba7ec5e47/coverage-7.10.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a3e853cc04987c85ec410905667eed4bf08b1d84d80dfab2684bb250ac8da4f6", size = 215328, upload-time = "2025-08-04T00:34:23.991Z" }, - { url = "https://files.pythonhosted.org/packages/1d/6c/30827a9c5a48a813e865fbaf91e2db25cce990bd223a022650ef2293fe11/coverage-7.10.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0100b19f230df72c90fdb36db59d3f39232391e8d89616a7de30f677da4f532b", size = 215608, upload-time = "2025-08-04T00:34:25.437Z" }, - { url = "https://files.pythonhosted.org/packages/bb/a0/c92d85948056ddc397b72a3d79d36d9579c53cb25393ed3c40db7d33b193/coverage-7.10.2-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9c1cd71483ea78331bdfadb8dcec4f4edfb73c7002c1206d8e0af6797853f5be", size = 246111, upload-time = "2025-08-04T00:34:26.857Z" }, - { url = "https://files.pythonhosted.org/packages/c2/cf/d695cf86b2559aadd072c91720a7844be4fb82cb4a3b642a2c6ce075692d/coverage-7.10.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9f75dbf4899e29a37d74f48342f29279391668ef625fdac6d2f67363518056a1", size = 248419, upload-time = "2025-08-04T00:34:28.726Z" }, - { url = "https://files.pythonhosted.org/packages/ce/0a/03206aec4a05986e039418c038470d874045f6e00426b0c3879adc1f9251/coverage-7.10.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a7df481e7508de1c38b9b8043da48d94931aefa3e32b47dd20277e4978ed5b95", size = 250038, upload-time = "2025-08-04T00:34:30.061Z" }, - { url = "https://files.pythonhosted.org/packages/ab/9b/b3bd6bd52118c12bc4cf319f5baba65009c9beea84e665b6b9f03fa3f180/coverage-7.10.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:835f39e618099325e7612b3406f57af30ab0a0af350490eff6421e2e5f608e46", size = 248066, upload-time = "2025-08-04T00:34:31.53Z" }, - { url = "https://files.pythonhosted.org/packages/80/cc/bfa92e261d3e055c851a073e87ba6a3bff12a1f7134233e48a8f7d855875/coverage-7.10.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:12e52b5aa00aa720097d6947d2eb9e404e7c1101ad775f9661ba165ed0a28303", size = 245909, upload-time = "2025-08-04T00:34:32.943Z" }, - { url = "https://files.pythonhosted.org/packages/12/80/c8df15db4847710c72084164f615ae900af1ec380dce7f74a5678ccdf5e1/coverage-7.10.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:718044729bf1fe3e9eb9f31b52e44ddae07e434ec050c8c628bf5adc56fe4bdd", size = 247329, upload-time = "2025-08-04T00:34:34.388Z" }, - { url = "https://files.pythonhosted.org/packages/04/6f/cb66e1f7124d5dd9ced69f889f02931419cb448125e44a89a13f4e036124/coverage-7.10.2-cp314-cp314-win32.whl", hash = "sha256:f256173b48cc68486299d510a3e729a96e62c889703807482dbf56946befb5c8", size = 218007, upload-time = "2025-08-04T00:34:35.846Z" }, - { url = "https://files.pythonhosted.org/packages/8c/e1/3d4be307278ce32c1b9d95cc02ee60d54ddab784036101d053ec9e4fe7f5/coverage-7.10.2-cp314-cp314-win_amd64.whl", hash = "sha256:2e980e4179f33d9b65ac4acb86c9c0dde904098853f27f289766657ed16e07b3", size = 218802, upload-time = "2025-08-04T00:34:37.35Z" }, - { url = "https://files.pythonhosted.org/packages/ec/66/1e43bbeb66c55a5a5efec70f1c153cf90cfc7f1662ab4ebe2d844de9122c/coverage-7.10.2-cp314-cp314-win_arm64.whl", hash = "sha256:14fb5b6641ab5b3c4161572579f0f2ea8834f9d3af2f7dd8fbaecd58ef9175cc", size = 217397, upload-time = "2025-08-04T00:34:39.15Z" }, - { url = "https://files.pythonhosted.org/packages/81/01/ae29c129217f6110dc694a217475b8aecbb1b075d8073401f868c825fa99/coverage-7.10.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:e96649ac34a3d0e6491e82a2af71098e43be2874b619547c3282fc11d3840a4b", size = 216068, upload-time = "2025-08-04T00:34:40.648Z" }, - { url = "https://files.pythonhosted.org/packages/a2/50/6e9221d4139f357258f36dfa1d8cac4ec56d9d5acf5fdcc909bb016954d7/coverage-7.10.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1a2e934e9da26341d342d30bfe91422bbfdb3f1f069ec87f19b2909d10d8dcc4", size = 216285, upload-time = "2025-08-04T00:34:42.441Z" }, - { url = "https://files.pythonhosted.org/packages/eb/ec/89d1d0c0ece0d296b4588e0ef4df185200456d42a47f1141335f482c2fc5/coverage-7.10.2-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:651015dcd5fd9b5a51ca79ece60d353cacc5beaf304db750407b29c89f72fe2b", size = 257603, upload-time = "2025-08-04T00:34:43.899Z" }, - { url = "https://files.pythonhosted.org/packages/82/06/c830af66734671c778fc49d35b58339e8f0687fbd2ae285c3f96c94da092/coverage-7.10.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:81bf6a32212f9f66da03d63ecb9cd9bd48e662050a937db7199dbf47d19831de", size = 259568, upload-time = "2025-08-04T00:34:45.519Z" }, - { url = "https://files.pythonhosted.org/packages/60/57/f280dd6f1c556ecc744fbf39e835c33d3ae987d040d64d61c6f821e87829/coverage-7.10.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d800705f6951f75a905ea6feb03fff8f3ea3468b81e7563373ddc29aa3e5d1ca", size = 261691, upload-time = "2025-08-04T00:34:47.019Z" }, - { url = "https://files.pythonhosted.org/packages/54/2b/c63a0acbd19d99ec32326164c23df3a4e18984fb86e902afdd66ff7b3d83/coverage-7.10.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:248b5394718e10d067354448dc406d651709c6765669679311170da18e0e9af8", size = 259166, upload-time = "2025-08-04T00:34:48.792Z" }, - { url = "https://files.pythonhosted.org/packages/fd/c5/cd2997dcfcbf0683634da9df52d3967bc1f1741c1475dd0e4722012ba9ef/coverage-7.10.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:5c61675a922b569137cf943770d7ad3edd0202d992ce53ac328c5ff68213ccf4", size = 257241, upload-time = "2025-08-04T00:34:51.038Z" }, - { url = "https://files.pythonhosted.org/packages/16/26/c9e30f82fdad8d47aee90af4978b18c88fa74369ae0f0ba0dbf08cee3a80/coverage-7.10.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:52d708b5fd65589461381fa442d9905f5903d76c086c6a4108e8e9efdca7a7ed", size = 258139, upload-time = "2025-08-04T00:34:52.533Z" }, - { url = "https://files.pythonhosted.org/packages/c9/99/bdb7bd00bebcd3dedfb895fa9af8e46b91422993e4a37ac634a5f1113790/coverage-7.10.2-cp314-cp314t-win32.whl", hash = "sha256:916369b3b914186b2c5e5ad2f7264b02cff5df96cdd7cdad65dccd39aa5fd9f0", size = 218809, upload-time = "2025-08-04T00:34:54.075Z" }, - { url = "https://files.pythonhosted.org/packages/eb/5e/56a7852e38a04d1520dda4dfbfbf74a3d6dec932c20526968f7444763567/coverage-7.10.2-cp314-cp314t-win_amd64.whl", hash = "sha256:5b9d538e8e04916a5df63052d698b30c74eb0174f2ca9cd942c981f274a18eaf", size = 219926, upload-time = "2025-08-04T00:34:55.643Z" }, - { url = "https://files.pythonhosted.org/packages/e0/12/7fbe6b9c52bb9d627e9556f9f2edfdbe88b315e084cdecc9afead0c3b36a/coverage-7.10.2-cp314-cp314t-win_arm64.whl", hash = "sha256:04c74f9ef1f925456a9fd23a7eef1103126186d0500ef9a0acb0bd2514bdc7cc", size = 217925, upload-time = "2025-08-04T00:34:57.564Z" }, - { url = "https://files.pythonhosted.org/packages/f5/c9/139fa9f64edfa5bae1492a4efecef7209f59ba5f9d862db594be7a85d7fb/coverage-7.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:765b13b164685a2f8b2abef867ad07aebedc0e090c757958a186f64e39d63dbd", size = 215003, upload-time = "2025-08-04T00:34:59.079Z" }, - { url = "https://files.pythonhosted.org/packages/fd/9f/8682ccdd223c2ab34de6575ef3c78fae9bdaece1710b4d95bb9b0abd4d2f/coverage-7.10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a219b70100500d0c7fd3ebb824a3302efb6b1a122baa9d4eb3f43df8f0b3d899", size = 215382, upload-time = "2025-08-04T00:35:00.772Z" }, - { url = "https://files.pythonhosted.org/packages/ab/4e/45b9658499db7149e1ed5b46ccac6101dc5c0ddb786a0304f7bb0c0d90d4/coverage-7.10.2-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e33e79a219105aa315439ee051bd50b6caa705dc4164a5aba6932c8ac3ce2d98", size = 241457, upload-time = "2025-08-04T00:35:02.696Z" }, - { url = "https://files.pythonhosted.org/packages/dd/66/aaf159bfe94ee3996b8786034a8e713bc68cd650aa7c1a41b612846cdc41/coverage-7.10.2-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bc3945b7bad33957a9eca16e9e5eae4b17cb03173ef594fdaad228f4fc7da53b", size = 243354, upload-time = "2025-08-04T00:35:04.238Z" }, - { url = "https://files.pythonhosted.org/packages/21/31/8fd2f67d8580380e7b19b23838e308b6757197e94a1b3b87e0ad483f70c8/coverage-7.10.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9bdff88e858ee608a924acfad32a180d2bf6e13e059d6a7174abbae075f30436", size = 244923, upload-time = "2025-08-04T00:35:06.159Z" }, - { url = "https://files.pythonhosted.org/packages/55/90/67b129b08200e08962961f56604083923bc8484bc641c92ee6801c1ae822/coverage-7.10.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:44329cbed24966c0b49acb386352c9722219af1f0c80db7f218af7793d251902", size = 242856, upload-time = "2025-08-04T00:35:07.735Z" }, - { url = "https://files.pythonhosted.org/packages/4d/8f/3f428363f713ab3432e602665cdefe436fd427263471644dd3742b6eebd8/coverage-7.10.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:be127f292496d0fbe20d8025f73221b36117b3587f890346e80a13b310712982", size = 241092, upload-time = "2025-08-04T00:35:09.381Z" }, - { url = "https://files.pythonhosted.org/packages/ac/4d/e8531ea19f047b8b1d1d1c85794e4b35ae762e570f072ca2afbce67be176/coverage-7.10.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6c031da749a05f7a01447dd7f47beedb498edd293e31e1878c0d52db18787df0", size = 242044, upload-time = "2025-08-04T00:35:10.929Z" }, - { url = "https://files.pythonhosted.org/packages/62/6b/22cb6281b4d06b73edae2facc7935a15151ddb8e8d8928a184b7a3100289/coverage-7.10.2-cp39-cp39-win32.whl", hash = "sha256:22aca3e691c7709c5999ccf48b7a8ff5cf5a8bd6fe9b36efbd4993f5a36b2fcf", size = 217512, upload-time = "2025-08-04T00:35:12.801Z" }, - { url = "https://files.pythonhosted.org/packages/9e/83/bce22e6880837de640d6ff630c7493709a3511f93c5154a326b337f01a81/coverage-7.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:c7195444b932356055a8e287fa910bf9753a84a1bc33aeb3770e8fca521e032e", size = 218406, upload-time = "2025-08-04T00:35:14.351Z" }, - { url = "https://files.pythonhosted.org/packages/18/d8/9b768ac73a8ac2d10c080af23937212434a958c8d2a1c84e89b450237942/coverage-7.10.2-py3-none-any.whl", hash = "sha256:95db3750dd2e6e93d99fa2498f3a1580581e49c494bddccc6f85c5c21604921f", size = 206973, upload-time = "2025-08-04T00:35:15.918Z" }, + { url = "https://files.pythonhosted.org/packages/2f/44/e14576c34b37764c821866909788ff7463228907ab82bae188dab2b421f1/coverage-7.10.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:53808194afdf948c462215e9403cca27a81cf150d2f9b386aee4dab614ae2ffe", size = 215964, upload-time = "2025-08-10T21:25:22.828Z" }, + { url = "https://files.pythonhosted.org/packages/e6/15/f4f92d9b83100903efe06c9396ee8d8bdba133399d37c186fc5b16d03a87/coverage-7.10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f4d1b837d1abf72187a61645dbf799e0d7705aa9232924946e1f57eb09a3bf00", size = 216361, upload-time = "2025-08-10T21:25:25.603Z" }, + { url = "https://files.pythonhosted.org/packages/e9/3a/c92e8cd5e89acc41cfc026dfb7acedf89661ce2ea1ee0ee13aacb6b2c20c/coverage-7.10.3-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2a90dd4505d3cc68b847ab10c5ee81822a968b5191664e8a0801778fa60459fa", size = 243115, upload-time = "2025-08-10T21:25:27.09Z" }, + { url = "https://files.pythonhosted.org/packages/23/53/c1d8c2778823b1d95ca81701bb8f42c87dc341a2f170acdf716567523490/coverage-7.10.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d52989685ff5bf909c430e6d7f6550937bc6d6f3e6ecb303c97a86100efd4596", size = 244927, upload-time = "2025-08-10T21:25:28.77Z" }, + { url = "https://files.pythonhosted.org/packages/79/41/1e115fd809031f432b4ff8e2ca19999fb6196ab95c35ae7ad5e07c001130/coverage-7.10.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bdb558a1d97345bde3a9f4d3e8d11c9e5611f748646e9bb61d7d612a796671b5", size = 246784, upload-time = "2025-08-10T21:25:30.195Z" }, + { url = "https://files.pythonhosted.org/packages/c7/b2/0eba9bdf8f1b327ae2713c74d4b7aa85451bb70622ab4e7b8c000936677c/coverage-7.10.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c9e6331a8f09cb1fc8bda032752af03c366870b48cce908875ba2620d20d0ad4", size = 244828, upload-time = "2025-08-10T21:25:31.785Z" }, + { url = "https://files.pythonhosted.org/packages/1f/cc/74c56b6bf71f2a53b9aa3df8bc27163994e0861c065b4fe3a8ac290bed35/coverage-7.10.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:992f48bf35b720e174e7fae916d943599f1a66501a2710d06c5f8104e0756ee1", size = 242844, upload-time = "2025-08-10T21:25:33.37Z" }, + { url = "https://files.pythonhosted.org/packages/b6/7b/ac183fbe19ac5596c223cb47af5737f4437e7566100b7e46cc29b66695a5/coverage-7.10.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c5595fc4ad6a39312c786ec3326d7322d0cf10e3ac6a6df70809910026d67cfb", size = 243721, upload-time = "2025-08-10T21:25:34.939Z" }, + { url = "https://files.pythonhosted.org/packages/57/96/cb90da3b5a885af48f531905234a1e7376acfc1334242183d23154a1c285/coverage-7.10.3-cp310-cp310-win32.whl", hash = "sha256:9e92fa1f2bd5a57df9d00cf9ce1eb4ef6fccca4ceabec1c984837de55329db34", size = 218481, upload-time = "2025-08-10T21:25:36.935Z" }, + { url = "https://files.pythonhosted.org/packages/15/67/1ba4c7d75745c4819c54a85766e0a88cc2bff79e1760c8a2debc34106dc2/coverage-7.10.3-cp310-cp310-win_amd64.whl", hash = "sha256:b96524d6e4a3ce6a75c56bb15dbd08023b0ae2289c254e15b9fbdddf0c577416", size = 219382, upload-time = "2025-08-10T21:25:38.267Z" }, + { url = "https://files.pythonhosted.org/packages/87/04/810e506d7a19889c244d35199cbf3239a2f952b55580aa42ca4287409424/coverage-7.10.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f2ff2e2afdf0d51b9b8301e542d9c21a8d084fd23d4c8ea2b3a1b3c96f5f7397", size = 216075, upload-time = "2025-08-10T21:25:39.891Z" }, + { url = "https://files.pythonhosted.org/packages/2e/50/6b3fbab034717b4af3060bdaea6b13dfdc6b1fad44b5082e2a95cd378a9a/coverage-7.10.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:18ecc5d1b9a8c570f6c9b808fa9a2b16836b3dd5414a6d467ae942208b095f85", size = 216476, upload-time = "2025-08-10T21:25:41.137Z" }, + { url = "https://files.pythonhosted.org/packages/c7/96/4368c624c1ed92659812b63afc76c492be7867ac8e64b7190b88bb26d43c/coverage-7.10.3-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1af4461b25fe92889590d438905e1fc79a95680ec2a1ff69a591bb3fdb6c7157", size = 246865, upload-time = "2025-08-10T21:25:42.408Z" }, + { url = "https://files.pythonhosted.org/packages/34/12/5608f76070939395c17053bf16e81fd6c06cf362a537ea9d07e281013a27/coverage-7.10.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3966bc9a76b09a40dc6063c8b10375e827ea5dfcaffae402dd65953bef4cba54", size = 248800, upload-time = "2025-08-10T21:25:44.098Z" }, + { url = "https://files.pythonhosted.org/packages/ce/52/7cc90c448a0ad724283cbcdfd66b8d23a598861a6a22ac2b7b8696491798/coverage-7.10.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:205a95b87ef4eb303b7bc5118b47b6b6604a644bcbdb33c336a41cfc0a08c06a", size = 250904, upload-time = "2025-08-10T21:25:45.384Z" }, + { url = "https://files.pythonhosted.org/packages/e6/70/9967b847063c1c393b4f4d6daab1131558ebb6b51f01e7df7150aa99f11d/coverage-7.10.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b3801b79fb2ad61e3c7e2554bab754fc5f105626056980a2b9cf3aef4f13f84", size = 248597, upload-time = "2025-08-10T21:25:47.059Z" }, + { url = "https://files.pythonhosted.org/packages/2d/fe/263307ce6878b9ed4865af42e784b42bb82d066bcf10f68defa42931c2c7/coverage-7.10.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b0dc69c60224cda33d384572da945759756e3f06b9cdac27f302f53961e63160", size = 246647, upload-time = "2025-08-10T21:25:48.334Z" }, + { url = "https://files.pythonhosted.org/packages/8e/27/d27af83ad162eba62c4eb7844a1de6cf7d9f6b185df50b0a3514a6f80ddd/coverage-7.10.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a83d4f134bab2c7ff758e6bb1541dd72b54ba295ced6a63d93efc2e20cb9b124", size = 247290, upload-time = "2025-08-10T21:25:49.945Z" }, + { url = "https://files.pythonhosted.org/packages/28/83/904ff27e15467a5622dbe9ad2ed5831b4a616a62570ec5924d06477dff5a/coverage-7.10.3-cp311-cp311-win32.whl", hash = "sha256:54e409dd64e5302b2a8fdf44ec1c26f47abd1f45a2dcf67bd161873ee05a59b8", size = 218521, upload-time = "2025-08-10T21:25:51.208Z" }, + { url = "https://files.pythonhosted.org/packages/b8/29/bc717b8902faaccf0ca486185f0dcab4778561a529dde51cb157acaafa16/coverage-7.10.3-cp311-cp311-win_amd64.whl", hash = "sha256:30c601610a9b23807c5e9e2e442054b795953ab85d525c3de1b1b27cebeb2117", size = 219412, upload-time = "2025-08-10T21:25:52.494Z" }, + { url = "https://files.pythonhosted.org/packages/7b/7a/5a1a7028c11bb589268c656c6b3f2bbf06e0aced31bbdf7a4e94e8442cc0/coverage-7.10.3-cp311-cp311-win_arm64.whl", hash = "sha256:dabe662312a97958e932dee056f2659051d822552c0b866823e8ba1c2fe64770", size = 218091, upload-time = "2025-08-10T21:25:54.102Z" }, + { url = "https://files.pythonhosted.org/packages/b8/62/13c0b66e966c43d7aa64dadc8cd2afa1f5a2bf9bb863bdabc21fb94e8b63/coverage-7.10.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:449c1e2d3a84d18bd204258a897a87bc57380072eb2aded6a5b5226046207b42", size = 216262, upload-time = "2025-08-10T21:25:55.367Z" }, + { url = "https://files.pythonhosted.org/packages/b5/f0/59fdf79be7ac2f0206fc739032f482cfd3f66b18f5248108ff192741beae/coverage-7.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1d4f9ce50b9261ad196dc2b2e9f1fbbee21651b54c3097a25ad783679fd18294", size = 216496, upload-time = "2025-08-10T21:25:56.759Z" }, + { url = "https://files.pythonhosted.org/packages/34/b1/bc83788ba31bde6a0c02eb96bbc14b2d1eb083ee073beda18753fa2c4c66/coverage-7.10.3-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4dd4564207b160d0d45c36a10bc0a3d12563028e8b48cd6459ea322302a156d7", size = 247989, upload-time = "2025-08-10T21:25:58.067Z" }, + { url = "https://files.pythonhosted.org/packages/0c/29/f8bdf88357956c844bd872e87cb16748a37234f7f48c721dc7e981145eb7/coverage-7.10.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5ca3c9530ee072b7cb6a6ea7b640bcdff0ad3b334ae9687e521e59f79b1d0437", size = 250738, upload-time = "2025-08-10T21:25:59.406Z" }, + { url = "https://files.pythonhosted.org/packages/ae/df/6396301d332b71e42bbe624670af9376f63f73a455cc24723656afa95796/coverage-7.10.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b6df359e59fa243c9925ae6507e27f29c46698359f45e568fd51b9315dbbe587", size = 251868, upload-time = "2025-08-10T21:26:00.65Z" }, + { url = "https://files.pythonhosted.org/packages/91/21/d760b2df6139b6ef62c9cc03afb9bcdf7d6e36ed4d078baacffa618b4c1c/coverage-7.10.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a181e4c2c896c2ff64c6312db3bda38e9ade2e1aa67f86a5628ae85873786cea", size = 249790, upload-time = "2025-08-10T21:26:02.009Z" }, + { url = "https://files.pythonhosted.org/packages/69/91/5dcaa134568202397fa4023d7066d4318dc852b53b428052cd914faa05e1/coverage-7.10.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a374d4e923814e8b72b205ef6b3d3a647bb50e66f3558582eda074c976923613", size = 247907, upload-time = "2025-08-10T21:26:03.757Z" }, + { url = "https://files.pythonhosted.org/packages/38/ed/70c0e871cdfef75f27faceada461206c1cc2510c151e1ef8d60a6fedda39/coverage-7.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:daeefff05993e5e8c6e7499a8508e7bd94502b6b9a9159c84fd1fe6bce3151cb", size = 249344, upload-time = "2025-08-10T21:26:05.11Z" }, + { url = "https://files.pythonhosted.org/packages/5f/55/c8a273ed503cedc07f8a00dcd843daf28e849f0972e4c6be4c027f418ad6/coverage-7.10.3-cp312-cp312-win32.whl", hash = "sha256:187ecdcac21f9636d570e419773df7bd2fda2e7fa040f812e7f95d0bddf5f79a", size = 218693, upload-time = "2025-08-10T21:26:06.534Z" }, + { url = "https://files.pythonhosted.org/packages/94/58/dd3cfb2473b85be0b6eb8c5b6d80b6fc3f8f23611e69ef745cef8cf8bad5/coverage-7.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:4a50ad2524ee7e4c2a95e60d2b0b83283bdfc745fe82359d567e4f15d3823eb5", size = 219501, upload-time = "2025-08-10T21:26:08.195Z" }, + { url = "https://files.pythonhosted.org/packages/56/af/7cbcbf23d46de6f24246e3f76b30df099d05636b30c53c158a196f7da3ad/coverage-7.10.3-cp312-cp312-win_arm64.whl", hash = "sha256:c112f04e075d3495fa3ed2200f71317da99608cbb2e9345bdb6de8819fc30571", size = 218135, upload-time = "2025-08-10T21:26:09.584Z" }, + { url = "https://files.pythonhosted.org/packages/0a/ff/239e4de9cc149c80e9cc359fab60592365b8c4cbfcad58b8a939d18c6898/coverage-7.10.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b99e87304ffe0eb97c5308447328a584258951853807afdc58b16143a530518a", size = 216298, upload-time = "2025-08-10T21:26:10.973Z" }, + { url = "https://files.pythonhosted.org/packages/56/da/28717da68f8ba68f14b9f558aaa8f3e39ada8b9a1ae4f4977c8f98b286d5/coverage-7.10.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4af09c7574d09afbc1ea7da9dcea23665c01f3bc1b1feb061dac135f98ffc53a", size = 216546, upload-time = "2025-08-10T21:26:12.616Z" }, + { url = "https://files.pythonhosted.org/packages/de/bb/e1ade16b9e3f2d6c323faeb6bee8e6c23f3a72760a5d9af102ef56a656cb/coverage-7.10.3-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:488e9b50dc5d2aa9521053cfa706209e5acf5289e81edc28291a24f4e4488f46", size = 247538, upload-time = "2025-08-10T21:26:14.455Z" }, + { url = "https://files.pythonhosted.org/packages/ea/2f/6ae1db51dc34db499bfe340e89f79a63bd115fc32513a7bacdf17d33cd86/coverage-7.10.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:913ceddb4289cbba3a310704a424e3fb7aac2bc0c3a23ea473193cb290cf17d4", size = 250141, upload-time = "2025-08-10T21:26:15.787Z" }, + { url = "https://files.pythonhosted.org/packages/4f/ed/33efd8819895b10c66348bf26f011dd621e804866c996ea6893d682218df/coverage-7.10.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b1f91cbc78c7112ab84ed2a8defbccd90f888fcae40a97ddd6466b0bec6ae8a", size = 251415, upload-time = "2025-08-10T21:26:17.535Z" }, + { url = "https://files.pythonhosted.org/packages/26/04/cb83826f313d07dc743359c9914d9bc460e0798da9a0e38b4f4fabc207ed/coverage-7.10.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0bac054d45af7cd938834b43a9878b36ea92781bcb009eab040a5b09e9927e3", size = 249575, upload-time = "2025-08-10T21:26:18.921Z" }, + { url = "https://files.pythonhosted.org/packages/2d/fd/ae963c7a8e9581c20fa4355ab8940ca272554d8102e872dbb932a644e410/coverage-7.10.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fe72cbdd12d9e0f4aca873fa6d755e103888a7f9085e4a62d282d9d5b9f7928c", size = 247466, upload-time = "2025-08-10T21:26:20.263Z" }, + { url = "https://files.pythonhosted.org/packages/99/e8/b68d1487c6af370b8d5ef223c6d7e250d952c3acfbfcdbf1a773aa0da9d2/coverage-7.10.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c1e2e927ab3eadd7c244023927d646e4c15c65bb2ac7ae3c3e9537c013700d21", size = 249084, upload-time = "2025-08-10T21:26:21.638Z" }, + { url = "https://files.pythonhosted.org/packages/66/4d/a0bcb561645c2c1e21758d8200443669d6560d2a2fb03955291110212ec4/coverage-7.10.3-cp313-cp313-win32.whl", hash = "sha256:24d0c13de473b04920ddd6e5da3c08831b1170b8f3b17461d7429b61cad59ae0", size = 218735, upload-time = "2025-08-10T21:26:23.009Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c3/78b4adddbc0feb3b223f62761e5f9b4c5a758037aaf76e0a5845e9e35e48/coverage-7.10.3-cp313-cp313-win_amd64.whl", hash = "sha256:3564aae76bce4b96e2345cf53b4c87e938c4985424a9be6a66ee902626edec4c", size = 219531, upload-time = "2025-08-10T21:26:24.474Z" }, + { url = "https://files.pythonhosted.org/packages/70/1b/1229c0b2a527fa5390db58d164aa896d513a1fbb85a1b6b6676846f00552/coverage-7.10.3-cp313-cp313-win_arm64.whl", hash = "sha256:f35580f19f297455f44afcd773c9c7a058e52eb6eb170aa31222e635f2e38b87", size = 218162, upload-time = "2025-08-10T21:26:25.847Z" }, + { url = "https://files.pythonhosted.org/packages/fc/26/1c1f450e15a3bf3eaecf053ff64538a2612a23f05b21d79ce03be9ff5903/coverage-7.10.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07009152f497a0464ffdf2634586787aea0e69ddd023eafb23fc38267db94b84", size = 217003, upload-time = "2025-08-10T21:26:27.231Z" }, + { url = "https://files.pythonhosted.org/packages/29/96/4b40036181d8c2948454b458750960956a3c4785f26a3c29418bbbee1666/coverage-7.10.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8dd2ba5f0c7e7e8cc418be2f0c14c4d9e3f08b8fb8e4c0f83c2fe87d03eb655e", size = 217238, upload-time = "2025-08-10T21:26:28.83Z" }, + { url = "https://files.pythonhosted.org/packages/62/23/8dfc52e95da20957293fb94d97397a100e63095ec1e0ef5c09dd8c6f591a/coverage-7.10.3-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1ae22b97003c74186e034a93e4f946c75fad8c0ce8d92fbbc168b5e15ee2841f", size = 258561, upload-time = "2025-08-10T21:26:30.475Z" }, + { url = "https://files.pythonhosted.org/packages/59/95/00e7fcbeda3f632232f4c07dde226afe3511a7781a000aa67798feadc535/coverage-7.10.3-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:eb329f1046888a36b1dc35504d3029e1dd5afe2196d94315d18c45ee380f67d5", size = 260735, upload-time = "2025-08-10T21:26:32.333Z" }, + { url = "https://files.pythonhosted.org/packages/9e/4c/f4666cbc4571804ba2a65b078ff0de600b0b577dc245389e0bc9b69ae7ca/coverage-7.10.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce01048199a91f07f96ca3074b0c14021f4fe7ffd29a3e6a188ac60a5c3a4af8", size = 262960, upload-time = "2025-08-10T21:26:33.701Z" }, + { url = "https://files.pythonhosted.org/packages/c1/a5/8a9e8a7b12a290ed98b60f73d1d3e5e9ced75a4c94a0d1a671ce3ddfff2a/coverage-7.10.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:08b989a06eb9dfacf96d42b7fb4c9a22bafa370d245dc22fa839f2168c6f9fa1", size = 260515, upload-time = "2025-08-10T21:26:35.16Z" }, + { url = "https://files.pythonhosted.org/packages/86/11/bb59f7f33b2cac0c5b17db0d9d0abba9c90d9eda51a6e727b43bd5fce4ae/coverage-7.10.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:669fe0d4e69c575c52148511029b722ba8d26e8a3129840c2ce0522e1452b256", size = 258278, upload-time = "2025-08-10T21:26:36.539Z" }, + { url = "https://files.pythonhosted.org/packages/cc/22/3646f8903743c07b3e53fded0700fed06c580a980482f04bf9536657ac17/coverage-7.10.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3262d19092771c83f3413831d9904b1ccc5f98da5de4ffa4ad67f5b20c7aaf7b", size = 259408, upload-time = "2025-08-10T21:26:37.954Z" }, + { url = "https://files.pythonhosted.org/packages/d2/5c/6375e9d905da22ddea41cd85c30994b8b6f6c02e44e4c5744b76d16b026f/coverage-7.10.3-cp313-cp313t-win32.whl", hash = "sha256:cc0ee4b2ccd42cab7ee6be46d8a67d230cb33a0a7cd47a58b587a7063b6c6b0e", size = 219396, upload-time = "2025-08-10T21:26:39.426Z" }, + { url = "https://files.pythonhosted.org/packages/33/3b/7da37fd14412b8c8b6e73c3e7458fef6b1b05a37f990a9776f88e7740c89/coverage-7.10.3-cp313-cp313t-win_amd64.whl", hash = "sha256:03db599f213341e2960430984e04cf35fb179724e052a3ee627a068653cf4a7c", size = 220458, upload-time = "2025-08-10T21:26:40.905Z" }, + { url = "https://files.pythonhosted.org/packages/28/cc/59a9a70f17edab513c844ee7a5c63cf1057041a84cc725b46a51c6f8301b/coverage-7.10.3-cp313-cp313t-win_arm64.whl", hash = "sha256:46eae7893ba65f53c71284585a262f083ef71594f05ec5c85baf79c402369098", size = 218722, upload-time = "2025-08-10T21:26:42.362Z" }, + { url = "https://files.pythonhosted.org/packages/2d/84/bb773b51a06edbf1231b47dc810a23851f2796e913b335a0fa364773b842/coverage-7.10.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:bce8b8180912914032785850d8f3aacb25ec1810f5f54afc4a8b114e7a9b55de", size = 216280, upload-time = "2025-08-10T21:26:44.132Z" }, + { url = "https://files.pythonhosted.org/packages/92/a8/4d8ca9c111d09865f18d56facff64d5fa076a5593c290bd1cfc5dceb8dba/coverage-7.10.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07790b4b37d56608536f7c1079bd1aa511567ac2966d33d5cec9cf520c50a7c8", size = 216557, upload-time = "2025-08-10T21:26:45.598Z" }, + { url = "https://files.pythonhosted.org/packages/fe/b2/eb668bfc5060194bc5e1ccd6f664e8e045881cfee66c42a2aa6e6c5b26e8/coverage-7.10.3-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e79367ef2cd9166acedcbf136a458dfe9a4a2dd4d1ee95738fb2ee581c56f667", size = 247598, upload-time = "2025-08-10T21:26:47.081Z" }, + { url = "https://files.pythonhosted.org/packages/fd/b0/9faa4ac62c8822219dd83e5d0e73876398af17d7305968aed8d1606d1830/coverage-7.10.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:419d2a0f769f26cb1d05e9ccbc5eab4cb5d70231604d47150867c07822acbdf4", size = 250131, upload-time = "2025-08-10T21:26:48.65Z" }, + { url = "https://files.pythonhosted.org/packages/4e/90/203537e310844d4bf1bdcfab89c1e05c25025c06d8489b9e6f937ad1a9e2/coverage-7.10.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee221cf244757cdc2ac882e3062ab414b8464ad9c884c21e878517ea64b3fa26", size = 251485, upload-time = "2025-08-10T21:26:50.368Z" }, + { url = "https://files.pythonhosted.org/packages/b9/b2/9d894b26bc53c70a1fe503d62240ce6564256d6d35600bdb86b80e516e7d/coverage-7.10.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c2079d8cdd6f7373d628e14b3357f24d1db02c9dc22e6a007418ca7a2be0435a", size = 249488, upload-time = "2025-08-10T21:26:52.045Z" }, + { url = "https://files.pythonhosted.org/packages/b4/28/af167dbac5281ba6c55c933a0ca6675d68347d5aee39cacc14d44150b922/coverage-7.10.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:bd8df1f83c0703fa3ca781b02d36f9ec67ad9cb725b18d486405924f5e4270bd", size = 247419, upload-time = "2025-08-10T21:26:53.533Z" }, + { url = "https://files.pythonhosted.org/packages/f4/1c/9a4ddc9f0dcb150d4cd619e1c4bb39bcf694c6129220bdd1e5895d694dda/coverage-7.10.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6b4e25e0fa335c8aa26e42a52053f3786a61cc7622b4d54ae2dad994aa754fec", size = 248917, upload-time = "2025-08-10T21:26:55.11Z" }, + { url = "https://files.pythonhosted.org/packages/92/27/c6a60c7cbe10dbcdcd7fc9ee89d531dc04ea4c073800279bb269954c5a9f/coverage-7.10.3-cp314-cp314-win32.whl", hash = "sha256:d7c3d02c2866deb217dce664c71787f4b25420ea3eaf87056f44fb364a3528f5", size = 218999, upload-time = "2025-08-10T21:26:56.637Z" }, + { url = "https://files.pythonhosted.org/packages/36/09/a94c1369964ab31273576615d55e7d14619a1c47a662ed3e2a2fe4dee7d4/coverage-7.10.3-cp314-cp314-win_amd64.whl", hash = "sha256:9c8916d44d9e0fe6cdb2227dc6b0edd8bc6c8ef13438bbbf69af7482d9bb9833", size = 219801, upload-time = "2025-08-10T21:26:58.207Z" }, + { url = "https://files.pythonhosted.org/packages/23/59/f5cd2a80f401c01cf0f3add64a7b791b7d53fd6090a4e3e9ea52691cf3c4/coverage-7.10.3-cp314-cp314-win_arm64.whl", hash = "sha256:1007d6a2b3cf197c57105cc1ba390d9ff7f0bee215ced4dea530181e49c65ab4", size = 218381, upload-time = "2025-08-10T21:26:59.707Z" }, + { url = "https://files.pythonhosted.org/packages/73/3d/89d65baf1ea39e148ee989de6da601469ba93c1d905b17dfb0b83bd39c96/coverage-7.10.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:ebc8791d346410d096818788877d675ca55c91db87d60e8f477bd41c6970ffc6", size = 217019, upload-time = "2025-08-10T21:27:01.242Z" }, + { url = "https://files.pythonhosted.org/packages/7d/7d/d9850230cd9c999ce3a1e600f85c2fff61a81c301334d7a1faa1a5ba19c8/coverage-7.10.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f4e4d8e75f6fd3c6940ebeed29e3d9d632e1f18f6fb65d33086d99d4d073241", size = 217237, upload-time = "2025-08-10T21:27:03.442Z" }, + { url = "https://files.pythonhosted.org/packages/36/51/b87002d417202ab27f4a1cd6bd34ee3b78f51b3ddbef51639099661da991/coverage-7.10.3-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:24581ed69f132b6225a31b0228ae4885731cddc966f8a33fe5987288bdbbbd5e", size = 258735, upload-time = "2025-08-10T21:27:05.124Z" }, + { url = "https://files.pythonhosted.org/packages/1c/02/1f8612bfcb46fc7ca64a353fff1cd4ed932bb6e0b4e0bb88b699c16794b8/coverage-7.10.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ec151569ddfccbf71bac8c422dce15e176167385a00cd86e887f9a80035ce8a5", size = 260901, upload-time = "2025-08-10T21:27:06.68Z" }, + { url = "https://files.pythonhosted.org/packages/aa/3a/fe39e624ddcb2373908bd922756384bb70ac1c5009b0d1674eb326a3e428/coverage-7.10.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2ae8e7c56290b908ee817200c0b65929b8050bc28530b131fe7c6dfee3e7d86b", size = 263157, upload-time = "2025-08-10T21:27:08.398Z" }, + { url = "https://files.pythonhosted.org/packages/5e/89/496b6d5a10fa0d0691a633bb2b2bcf4f38f0bdfcbde21ad9e32d1af328ed/coverage-7.10.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5fb742309766d7e48e9eb4dc34bc95a424707bc6140c0e7d9726e794f11b92a0", size = 260597, upload-time = "2025-08-10T21:27:10.237Z" }, + { url = "https://files.pythonhosted.org/packages/b6/a6/8b5bf6a9e8c6aaeb47d5fe9687014148efc05c3588110246d5fdeef9b492/coverage-7.10.3-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:c65e2a5b32fbe1e499f1036efa6eb9cb4ea2bf6f7168d0e7a5852f3024f471b1", size = 258353, upload-time = "2025-08-10T21:27:11.773Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6d/ad131be74f8afd28150a07565dfbdc86592fd61d97e2dc83383d9af219f0/coverage-7.10.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d48d2cb07d50f12f4f18d2bb75d9d19e3506c26d96fffabf56d22936e5ed8f7c", size = 259504, upload-time = "2025-08-10T21:27:13.254Z" }, + { url = "https://files.pythonhosted.org/packages/ec/30/fc9b5097092758cba3375a8cc4ff61774f8cd733bcfb6c9d21a60077a8d8/coverage-7.10.3-cp314-cp314t-win32.whl", hash = "sha256:dec0d9bc15ee305e09fe2cd1911d3f0371262d3cfdae05d79515d8cb712b4869", size = 219782, upload-time = "2025-08-10T21:27:14.736Z" }, + { url = "https://files.pythonhosted.org/packages/72/9b/27fbf79451b1fac15c4bda6ec6e9deae27cf7c0648c1305aa21a3454f5c4/coverage-7.10.3-cp314-cp314t-win_amd64.whl", hash = "sha256:424ea93a323aa0f7f01174308ea78bde885c3089ec1bef7143a6d93c3e24ef64", size = 220898, upload-time = "2025-08-10T21:27:16.297Z" }, + { url = "https://files.pythonhosted.org/packages/d1/cf/a32bbf92869cbf0b7c8b84325327bfc718ad4b6d2c63374fef3d58e39306/coverage-7.10.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f5983c132a62d93d71c9ef896a0b9bf6e6828d8d2ea32611f58684fba60bba35", size = 218922, upload-time = "2025-08-10T21:27:18.22Z" }, + { url = "https://files.pythonhosted.org/packages/f1/66/c06f4a93c65b6fc6578ef4f1fe51f83d61fc6f2a74ec0ce434ed288d834a/coverage-7.10.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:da749daa7e141985487e1ff90a68315b0845930ed53dc397f4ae8f8bab25b551", size = 215951, upload-time = "2025-08-10T21:27:19.815Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ea/cc18c70a6f72f8e4def212eaebd8388c64f29608da10b3c38c8ec76f5e49/coverage-7.10.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3126fb6a47d287f461d9b1aa5d1a8c97034d1dffb4f452f2cf211289dae74ef", size = 216335, upload-time = "2025-08-10T21:27:21.737Z" }, + { url = "https://files.pythonhosted.org/packages/f2/fb/9c6d1d67c6d54b149f06b9f374bc9ca03e4d7d7784c8cfd12ceda20e3787/coverage-7.10.3-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3da794db13cc27ca40e1ec8127945b97fab78ba548040047d54e7bfa6d442dca", size = 242772, upload-time = "2025-08-10T21:27:23.884Z" }, + { url = "https://files.pythonhosted.org/packages/5a/e5/4223bdb28b992a19a13ab1410c761e2bfe92ca1e7bba8e85ee2024eeda85/coverage-7.10.3-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4e27bebbd184ef8d1c1e092b74a2b7109dcbe2618dce6e96b1776d53b14b3fe8", size = 244596, upload-time = "2025-08-10T21:27:25.842Z" }, + { url = "https://files.pythonhosted.org/packages/d2/13/d646ba28613669d487c654a760571c10128247d12d9f50e93f69542679a2/coverage-7.10.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8fd4ee2580b9fefbd301b4f8f85b62ac90d1e848bea54f89a5748cf132782118", size = 246370, upload-time = "2025-08-10T21:27:27.503Z" }, + { url = "https://files.pythonhosted.org/packages/02/7c/aff99c67d8c383142b0877ee435caf493765356336211c4899257325d6c7/coverage-7.10.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6999920bdd73259ce11cabfc1307484f071ecc6abdb2ca58d98facbcefc70f16", size = 244254, upload-time = "2025-08-10T21:27:29.357Z" }, + { url = "https://files.pythonhosted.org/packages/b0/13/a51ea145ed51ddfa8717bb29926d9111aca343fab38f04692a843d50be6b/coverage-7.10.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c3623f929db885fab100cb88220a5b193321ed37e03af719efdbaf5d10b6e227", size = 242325, upload-time = "2025-08-10T21:27:30.931Z" }, + { url = "https://files.pythonhosted.org/packages/d8/4b/6119be0089c89ad49d2e5a508d55a1485c878642b706a7f95b26e299137d/coverage-7.10.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:25b902c5e15dea056485d782e420bb84621cc08ee75d5131ecb3dbef8bd1365f", size = 243281, upload-time = "2025-08-10T21:27:32.815Z" }, + { url = "https://files.pythonhosted.org/packages/34/c8/1b2e7e53eee4bc1304e56e10361b08197a77a26ceb07201dcc9e759ef132/coverage-7.10.3-cp39-cp39-win32.whl", hash = "sha256:f930a4d92b004b643183451fe9c8fe398ccf866ed37d172ebaccfd443a097f61", size = 218489, upload-time = "2025-08-10T21:27:34.905Z" }, + { url = "https://files.pythonhosted.org/packages/dd/1e/9c0c230a199809c39e2dff0f1f889dfb04dcd07d83c1c26a8ef671660e08/coverage-7.10.3-cp39-cp39-win_amd64.whl", hash = "sha256:08e638a93c8acba13c7842953f92a33d52d73e410329acd472280d2a21a6c0e1", size = 219396, upload-time = "2025-08-10T21:27:36.61Z" }, + { url = "https://files.pythonhosted.org/packages/84/19/e67f4ae24e232c7f713337f3f4f7c9c58afd0c02866fb07c7b9255a19ed7/coverage-7.10.3-py3-none-any.whl", hash = "sha256:416a8d74dc0adfd33944ba2f405897bab87b7e9e84a391e09d241956bd953ce1", size = 207921, upload-time = "2025-08-10T21:27:38.254Z" }, ] [package.optional-dependencies] @@ -885,7 +884,7 @@ resolution-markers = [ "python_full_version == '3.9.*'", ] dependencies = [ - { name = "coverage", version = "7.10.2", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version >= '3.9'" }, + { name = "coverage", version = "7.10.3", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version >= '3.9'" }, { name = "pluggy", version = "1.6.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, { name = "pytest", version = "8.4.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, ] @@ -925,27 +924,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.12.7" +version = "0.12.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/81/0bd3594fa0f690466e41bd033bdcdf86cba8288345ac77ad4afbe5ec743a/ruff-0.12.7.tar.gz", hash = "sha256:1fc3193f238bc2d7968772c82831a4ff69252f673be371fb49663f0068b7ec71", size = 5197814, upload-time = "2025-07-29T22:32:35.877Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4b/da/5bd7565be729e86e1442dad2c9a364ceeff82227c2dece7c29697a9795eb/ruff-0.12.8.tar.gz", hash = "sha256:4cb3a45525176e1009b2b64126acf5f9444ea59066262791febf55e40493a033", size = 5242373, upload-time = "2025-08-07T19:05:47.268Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/d2/6cb35e9c85e7a91e8d22ab32ae07ac39cc34a71f1009a6f9e4a2a019e602/ruff-0.12.7-py3-none-linux_armv6l.whl", hash = "sha256:76e4f31529899b8c434c3c1dede98c4483b89590e15fb49f2d46183801565303", size = 11852189, upload-time = "2025-07-29T22:31:41.281Z" }, - { url = "https://files.pythonhosted.org/packages/63/5b/a4136b9921aa84638f1a6be7fb086f8cad0fde538ba76bda3682f2599a2f/ruff-0.12.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:789b7a03e72507c54fb3ba6209e4bb36517b90f1a3569ea17084e3fd295500fb", size = 12519389, upload-time = "2025-07-29T22:31:54.265Z" }, - { url = "https://files.pythonhosted.org/packages/a8/c9/3e24a8472484269b6b1821794141f879c54645a111ded4b6f58f9ab0705f/ruff-0.12.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2e1c2a3b8626339bb6369116e7030a4cf194ea48f49b64bb505732a7fce4f4e3", size = 11743384, upload-time = "2025-07-29T22:31:59.575Z" }, - { url = "https://files.pythonhosted.org/packages/26/7c/458dd25deeb3452c43eaee853c0b17a1e84169f8021a26d500ead77964fd/ruff-0.12.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32dec41817623d388e645612ec70d5757a6d9c035f3744a52c7b195a57e03860", size = 11943759, upload-time = "2025-07-29T22:32:01.95Z" }, - { url = "https://files.pythonhosted.org/packages/7f/8b/658798472ef260ca050e400ab96ef7e85c366c39cf3dfbef4d0a46a528b6/ruff-0.12.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47ef751f722053a5df5fa48d412dbb54d41ab9b17875c6840a58ec63ff0c247c", size = 11654028, upload-time = "2025-07-29T22:32:04.367Z" }, - { url = "https://files.pythonhosted.org/packages/a8/86/9c2336f13b2a3326d06d39178fd3448dcc7025f82514d1b15816fe42bfe8/ruff-0.12.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a828a5fc25a3efd3e1ff7b241fd392686c9386f20e5ac90aa9234a5faa12c423", size = 13225209, upload-time = "2025-07-29T22:32:06.952Z" }, - { url = "https://files.pythonhosted.org/packages/76/69/df73f65f53d6c463b19b6b312fd2391dc36425d926ec237a7ed028a90fc1/ruff-0.12.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5726f59b171111fa6a69d82aef48f00b56598b03a22f0f4170664ff4d8298efb", size = 14182353, upload-time = "2025-07-29T22:32:10.053Z" }, - { url = "https://files.pythonhosted.org/packages/58/1e/de6cda406d99fea84b66811c189b5ea139814b98125b052424b55d28a41c/ruff-0.12.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74e6f5c04c4dd4aba223f4fe6e7104f79e0eebf7d307e4f9b18c18362124bccd", size = 13631555, upload-time = "2025-07-29T22:32:12.644Z" }, - { url = "https://files.pythonhosted.org/packages/6f/ae/625d46d5164a6cc9261945a5e89df24457dc8262539ace3ac36c40f0b51e/ruff-0.12.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d0bfe4e77fba61bf2ccadf8cf005d6133e3ce08793bbe870dd1c734f2699a3e", size = 12667556, upload-time = "2025-07-29T22:32:15.312Z" }, - { url = "https://files.pythonhosted.org/packages/55/bf/9cb1ea5e3066779e42ade8d0cd3d3b0582a5720a814ae1586f85014656b6/ruff-0.12.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06bfb01e1623bf7f59ea749a841da56f8f653d641bfd046edee32ede7ff6c606", size = 12939784, upload-time = "2025-07-29T22:32:17.69Z" }, - { url = "https://files.pythonhosted.org/packages/55/7f/7ead2663be5627c04be83754c4f3096603bf5e99ed856c7cd29618c691bd/ruff-0.12.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e41df94a957d50083fd09b916d6e89e497246698c3f3d5c681c8b3e7b9bb4ac8", size = 11771356, upload-time = "2025-07-29T22:32:20.134Z" }, - { url = "https://files.pythonhosted.org/packages/17/40/a95352ea16edf78cd3a938085dccc55df692a4d8ba1b3af7accbe2c806b0/ruff-0.12.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4000623300563c709458d0ce170c3d0d788c23a058912f28bbadc6f905d67afa", size = 11612124, upload-time = "2025-07-29T22:32:22.645Z" }, - { url = "https://files.pythonhosted.org/packages/4d/74/633b04871c669e23b8917877e812376827c06df866e1677f15abfadc95cb/ruff-0.12.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:69ffe0e5f9b2cf2b8e289a3f8945b402a1b19eff24ec389f45f23c42a3dd6fb5", size = 12479945, upload-time = "2025-07-29T22:32:24.765Z" }, - { url = "https://files.pythonhosted.org/packages/be/34/c3ef2d7799c9778b835a76189c6f53c179d3bdebc8c65288c29032e03613/ruff-0.12.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a07a5c8ffa2611a52732bdc67bf88e243abd84fe2d7f6daef3826b59abbfeda4", size = 12998677, upload-time = "2025-07-29T22:32:27.022Z" }, - { url = "https://files.pythonhosted.org/packages/77/ab/aca2e756ad7b09b3d662a41773f3edcbd262872a4fc81f920dc1ffa44541/ruff-0.12.7-py3-none-win32.whl", hash = "sha256:c928f1b2ec59fb77dfdf70e0419408898b63998789cc98197e15f560b9e77f77", size = 11756687, upload-time = "2025-07-29T22:32:29.381Z" }, - { url = "https://files.pythonhosted.org/packages/b4/71/26d45a5042bc71db22ddd8252ca9d01e9ca454f230e2996bb04f16d72799/ruff-0.12.7-py3-none-win_amd64.whl", hash = "sha256:9c18f3d707ee9edf89da76131956aba1270c6348bfee8f6c647de841eac7194f", size = 12912365, upload-time = "2025-07-29T22:32:31.517Z" }, - { url = "https://files.pythonhosted.org/packages/4c/9b/0b8aa09817b63e78d94b4977f18b1fcaead3165a5ee49251c5d5c245bb2d/ruff-0.12.7-py3-none-win_arm64.whl", hash = "sha256:dfce05101dbd11833a0776716d5d1578641b7fddb537fe7fa956ab85d1769b69", size = 11982083, upload-time = "2025-07-29T22:32:33.881Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1e/c843bfa8ad1114fab3eb2b78235dda76acd66384c663a4e0415ecc13aa1e/ruff-0.12.8-py3-none-linux_armv6l.whl", hash = "sha256:63cb5a5e933fc913e5823a0dfdc3c99add73f52d139d6cd5cc8639d0e0465513", size = 11675315, upload-time = "2025-08-07T19:05:06.15Z" }, + { url = "https://files.pythonhosted.org/packages/24/ee/af6e5c2a8ca3a81676d5480a1025494fd104b8896266502bb4de2a0e8388/ruff-0.12.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9a9bbe28f9f551accf84a24c366c1aa8774d6748438b47174f8e8565ab9dedbc", size = 12456653, upload-time = "2025-08-07T19:05:09.759Z" }, + { url = "https://files.pythonhosted.org/packages/99/9d/e91f84dfe3866fa648c10512904991ecc326fd0b66578b324ee6ecb8f725/ruff-0.12.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2fae54e752a3150f7ee0e09bce2e133caf10ce9d971510a9b925392dc98d2fec", size = 11659690, upload-time = "2025-08-07T19:05:12.551Z" }, + { url = "https://files.pythonhosted.org/packages/fe/ac/a363d25ec53040408ebdd4efcee929d48547665858ede0505d1d8041b2e5/ruff-0.12.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0acbcf01206df963d9331b5838fb31f3b44fa979ee7fa368b9b9057d89f4a53", size = 11896923, upload-time = "2025-08-07T19:05:14.821Z" }, + { url = "https://files.pythonhosted.org/packages/58/9f/ea356cd87c395f6ade9bb81365bd909ff60860975ca1bc39f0e59de3da37/ruff-0.12.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae3e7504666ad4c62f9ac8eedb52a93f9ebdeb34742b8b71cd3cccd24912719f", size = 11477612, upload-time = "2025-08-07T19:05:16.712Z" }, + { url = "https://files.pythonhosted.org/packages/1a/46/92e8fa3c9dcfd49175225c09053916cb97bb7204f9f899c2f2baca69e450/ruff-0.12.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb82efb5d35d07497813a1c5647867390a7d83304562607f3579602fa3d7d46f", size = 13182745, upload-time = "2025-08-07T19:05:18.709Z" }, + { url = "https://files.pythonhosted.org/packages/5e/c4/f2176a310f26e6160deaf661ef60db6c3bb62b7a35e57ae28f27a09a7d63/ruff-0.12.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:dbea798fc0065ad0b84a2947b0aff4233f0cb30f226f00a2c5850ca4393de609", size = 14206885, upload-time = "2025-08-07T19:05:21.025Z" }, + { url = "https://files.pythonhosted.org/packages/87/9d/98e162f3eeeb6689acbedbae5050b4b3220754554526c50c292b611d3a63/ruff-0.12.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:49ebcaccc2bdad86fd51b7864e3d808aad404aab8df33d469b6e65584656263a", size = 13639381, upload-time = "2025-08-07T19:05:23.423Z" }, + { url = "https://files.pythonhosted.org/packages/81/4e/1b7478b072fcde5161b48f64774d6edd59d6d198e4ba8918d9f4702b8043/ruff-0.12.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ac9c570634b98c71c88cb17badd90f13fc076a472ba6ef1d113d8ed3df109fb", size = 12613271, upload-time = "2025-08-07T19:05:25.507Z" }, + { url = "https://files.pythonhosted.org/packages/e8/67/0c3c9179a3ad19791ef1b8f7138aa27d4578c78700551c60d9260b2c660d/ruff-0.12.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:560e0cd641e45591a3e42cb50ef61ce07162b9c233786663fdce2d8557d99818", size = 12847783, upload-time = "2025-08-07T19:05:28.14Z" }, + { url = "https://files.pythonhosted.org/packages/4e/2a/0b6ac3dd045acf8aa229b12c9c17bb35508191b71a14904baf99573a21bd/ruff-0.12.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:71c83121512e7743fba5a8848c261dcc454cafb3ef2934a43f1b7a4eb5a447ea", size = 11702672, upload-time = "2025-08-07T19:05:30.413Z" }, + { url = "https://files.pythonhosted.org/packages/9d/ee/f9fdc9f341b0430110de8b39a6ee5fa68c5706dc7c0aa940817947d6937e/ruff-0.12.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:de4429ef2ba091ecddedd300f4c3f24bca875d3d8b23340728c3cb0da81072c3", size = 11440626, upload-time = "2025-08-07T19:05:32.492Z" }, + { url = "https://files.pythonhosted.org/packages/89/fb/b3aa2d482d05f44e4d197d1de5e3863feb13067b22c571b9561085c999dc/ruff-0.12.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a2cab5f60d5b65b50fba39a8950c8746df1627d54ba1197f970763917184b161", size = 12462162, upload-time = "2025-08-07T19:05:34.449Z" }, + { url = "https://files.pythonhosted.org/packages/18/9f/5c5d93e1d00d854d5013c96e1a92c33b703a0332707a7cdbd0a4880a84fb/ruff-0.12.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:45c32487e14f60b88aad6be9fd5da5093dbefb0e3e1224131cb1d441d7cb7d46", size = 12913212, upload-time = "2025-08-07T19:05:36.541Z" }, + { url = "https://files.pythonhosted.org/packages/71/13/ab9120add1c0e4604c71bfc2e4ef7d63bebece0cfe617013da289539cef8/ruff-0.12.8-py3-none-win32.whl", hash = "sha256:daf3475060a617fd5bc80638aeaf2f5937f10af3ec44464e280a9d2218e720d3", size = 11694382, upload-time = "2025-08-07T19:05:38.468Z" }, + { url = "https://files.pythonhosted.org/packages/f6/dc/a2873b7c5001c62f46266685863bee2888caf469d1edac84bf3242074be2/ruff-0.12.8-py3-none-win_amd64.whl", hash = "sha256:7209531f1a1fcfbe8e46bcd7ab30e2f43604d8ba1c49029bb420b103d0b5f76e", size = 12740482, upload-time = "2025-08-07T19:05:40.391Z" }, + { url = "https://files.pythonhosted.org/packages/cb/5c/799a1efb8b5abab56e8a9f2a0b72d12bd64bb55815e9476c7d0a2887d2f7/ruff-0.12.8-py3-none-win_arm64.whl", hash = "sha256:c90e1a334683ce41b0e7a04f41790c429bf5073b62c1ae701c9dc5b3d14f0749", size = 11884718, upload-time = "2025-08-07T19:05:42.866Z" }, ] [[package]] diff --git a/xdk/python/xdk/aaasubscriptions/__init__.py b/xdk/python/xdk/aaasubscriptions/__init__.py index 81642824..02f9188a 100644 --- a/xdk/python/xdk/aaasubscriptions/__init__.py +++ b/xdk/python/xdk/aaasubscriptions/__init__.py @@ -1,9 +1,9 @@ """ -AAASubscriptions module for the X API. +aaasubscriptions module for the X API. -This module provides access to the AAASubscriptions endpoints of the X API. +This module provides access to the aaasubscriptions endpoints of the X API. """ -from .client import AAASubscriptionsClient +from .client import AaasubscriptionsClient -__all__ = ["AAASubscriptionsClient"] +__all__ = ["AaasubscriptionsClient"] diff --git a/xdk/python/xdk/aaasubscriptions/client.py b/xdk/python/xdk/aaasubscriptions/client.py index 2ecda001..433152c8 100644 --- a/xdk/python/xdk/aaasubscriptions/client.py +++ b/xdk/python/xdk/aaasubscriptions/client.py @@ -1,7 +1,7 @@ """ -AAASubscriptions client for the X API. +aaasubscriptions client for the X API. -This module provides a client for interacting with the AAASubscriptions endpoints of the X API. +This module provides a client for interacting with the aaasubscriptions endpoints of the X API. """ from __future__ import annotations @@ -17,8 +17,8 @@ ) -class AAASubscriptionsClient: - """Client for AAASubscriptions operations""" +class AaasubscriptionsClient: + """Client for aaasubscriptions operations""" def __init__(self, client: Client): @@ -27,7 +27,7 @@ def __init__(self, client: Client): def create_account_activity_subscription( self, - webhook_id: str, + webhook_id: Any, body: Optional[CreateAccountActivitySubscriptionRequest] = None, ) -> CreateAccountActivitySubscriptionResponse: """ diff --git a/xdk/python/xdk/aaasubscriptions/models.py b/xdk/python/xdk/aaasubscriptions/models.py index 97f14cba..3a3ded2f 100644 --- a/xdk/python/xdk/aaasubscriptions/models.py +++ b/xdk/python/xdk/aaasubscriptions/models.py @@ -1,7 +1,7 @@ """ -AAASubscriptions models for the X API. +aaasubscriptions models for the X API. -This module provides models for the AAASubscriptions endpoints of the X API. +This module provides models for the aaasubscriptions endpoints of the X API. """ from typing import Dict, List, Optional, Any, Union, Literal @@ -9,17 +9,17 @@ from datetime import datetime -# Models for createAccountActivitySubscription +# Models for create_account_activity_subscription class CreateAccountActivitySubscriptionRequest(BaseModel): - """Request model for createAccountActivitySubscription""" + """Request model for create_account_activity_subscription""" model_config = ConfigDict(populate_by_name=True) class CreateAccountActivitySubscriptionResponse(BaseModel): - """Response model for createAccountActivitySubscription""" + """Response model for create_account_activity_subscription""" data: Optional["CreateAccountActivitySubscriptionResponseData"] = None errors: Optional[List] = None diff --git a/xdk/python/xdk/account_activity/__init__.py b/xdk/python/xdk/account_activity/__init__.py index 799b0a4d..d6dba520 100644 --- a/xdk/python/xdk/account_activity/__init__.py +++ b/xdk/python/xdk/account_activity/__init__.py @@ -1,7 +1,7 @@ """ -Account_Activity module for the X API. +account activity module for the X API. -This module provides access to the Account_Activity endpoints of the X API. +This module provides access to the account activity endpoints of the X API. """ from .client import AccountActivityClient diff --git a/xdk/python/xdk/account_activity/client.py b/xdk/python/xdk/account_activity/client.py index 573789f5..329e1902 100644 --- a/xdk/python/xdk/account_activity/client.py +++ b/xdk/python/xdk/account_activity/client.py @@ -1,7 +1,7 @@ """ -Account_Activity client for the X API. +account activity client for the X API. -This module provides a client for interacting with the Account_Activity endpoints of the X API. +This module provides a client for interacting with the account activity endpoints of the X API. """ from __future__ import annotations @@ -12,33 +12,33 @@ if TYPE_CHECKING: from ..client import Client from .models import ( - GetAccountActivitySubscriptionsResponse, - ValidateAccountActivitySubscriptionResponse, - GetAccountActivitySubscriptionCountResponse, - DeleteAccountActivitySubscriptionResponse, - CreateAccountActivityReplayJobResponse, + GetSubscriptionsResponse, + ValidateSubscriptionResponse, + DeleteSubscriptionResponse, + GetSubscriptionCountResponse, + CreateReplayJobResponse, ) class AccountActivityClient: - """Client for Account_Activity operations""" + """Client for account activity operations""" def __init__(self, client: Client): self.client = client - def get_account_activity_subscriptions( + def get_subscriptions( self, - webhook_id: str, - ) -> GetAccountActivitySubscriptionsResponse: + webhook_id: Any, + ) -> GetSubscriptionsResponse: """ Get subscriptions Retrieves a list of all active subscriptions for a given webhook. Args: webhook_id: The webhook ID to pull subscriptions for. Returns: - GetAccountActivitySubscriptionsResponse: Response data + GetSubscriptionsResponse: Response data """ url = ( self.client.base_url @@ -66,20 +66,20 @@ def get_account_activity_subscriptions( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetAccountActivitySubscriptionsResponse.model_validate(response_data) + return GetSubscriptionsResponse.model_validate(response_data) - def validate_account_activity_subscription( + def validate_subscription( self, - webhook_id: str, - ) -> ValidateAccountActivitySubscriptionResponse: + webhook_id: Any, + ) -> ValidateSubscriptionResponse: """ Validate subscription Checks a user’s Account Activity subscription for a given webhook. Args: webhook_id: The webhook ID to check subscription against. Returns: - ValidateAccountActivitySubscriptionResponse: Response data + ValidateSubscriptionResponse: Response data """ url = ( self.client.base_url @@ -111,19 +111,28 @@ def validate_account_activity_subscription( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return ValidateAccountActivitySubscriptionResponse.model_validate(response_data) + return ValidateSubscriptionResponse.model_validate(response_data) - def get_account_activity_subscription_count( + def delete_subscription( self, - ) -> GetAccountActivitySubscriptionCountResponse: + webhook_id: Any, + user_id: Any, + ) -> DeleteSubscriptionResponse: """ - Get subscription count - Retrieves a count of currently active Account Activity subscriptions. + Delete subscription + Deletes an Account Activity subscription for the given webhook and user ID. + Args: + webhook_id: The webhook ID to check subscription against. + Args: + user_id: User ID to unsubscribe from. Returns: - GetAccountActivitySubscriptionCountResponse: Response data + DeleteSubscriptionResponse: Response data """ - url = self.client.base_url + "/2/account_activity/subscriptions/count" + url = ( + self.client.base_url + + "/2/account_activity/webhooks/{webhook_id}/subscriptions/{user_id}/all" + ) if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -133,9 +142,11 @@ def get_account_activity_subscription_count( f"Bearer {self.client.access_token}" ) params = {} + url = url.replace("{webhook_id}", str(webhook_id)) + url = url.replace("{user_id}", str(user_id)) headers = {} # Make the request - response = self.client.session.get( + response = self.client.session.delete( url, params=params, headers=headers, @@ -145,28 +156,19 @@ def get_account_activity_subscription_count( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetAccountActivitySubscriptionCountResponse.model_validate(response_data) + return DeleteSubscriptionResponse.model_validate(response_data) - def delete_account_activity_subscription( + def get_subscription_count( self, - webhook_id: str, - user_id: str, - ) -> DeleteAccountActivitySubscriptionResponse: + ) -> GetSubscriptionCountResponse: """ - Delete subscription - Deletes an Account Activity subscription for the given webhook and user ID. - Args: - webhook_id: The webhook ID to check subscription against. - Args: - user_id: User ID to unsubscribe from. + Get subscription count + Retrieves a count of currently active Account Activity subscriptions. Returns: - DeleteAccountActivitySubscriptionResponse: Response data + GetSubscriptionCountResponse: Response data """ - url = ( - self.client.base_url - + "/2/account_activity/webhooks/{webhook_id}/subscriptions/{user_id}/all" - ) + url = self.client.base_url + "/2/account_activity/subscriptions/count" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -176,11 +178,9 @@ def delete_account_activity_subscription( f"Bearer {self.client.access_token}" ) params = {} - url = url.replace("{webhook_id}", str(webhook_id)) - url = url.replace("{user_id}", str(user_id)) headers = {} # Make the request - response = self.client.session.delete( + response = self.client.session.get( url, params=params, headers=headers, @@ -190,15 +190,15 @@ def delete_account_activity_subscription( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return DeleteAccountActivitySubscriptionResponse.model_validate(response_data) + return GetSubscriptionCountResponse.model_validate(response_data) - def create_account_activity_replay_job( + def create_replay_job( self, - webhook_id: str, + webhook_id: Any, from_date: str, to_date: str, - ) -> CreateAccountActivityReplayJobResponse: + ) -> CreateReplayJobResponse: """ Create replay job Creates a replay job to retrieve activities from up to the past 5 days for all subscriptions associated with a given webhook. @@ -209,7 +209,7 @@ def create_account_activity_replay_job( Args: to_date: The latest (ending) UTC timestamp (exclusive) up to which events will be provided, in `yyyymmddhhmm` format. Returns: - CreateAccountActivityReplayJobResponse: Response data + CreateReplayJobResponse: Response data """ url = ( self.client.base_url @@ -241,4 +241,4 @@ def create_account_activity_replay_job( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return CreateAccountActivityReplayJobResponse.model_validate(response_data) + return CreateReplayJobResponse.model_validate(response_data) diff --git a/xdk/python/xdk/account_activity/models.py b/xdk/python/xdk/account_activity/models.py index c1b5199d..5b85f21b 100644 --- a/xdk/python/xdk/account_activity/models.py +++ b/xdk/python/xdk/account_activity/models.py @@ -1,7 +1,7 @@ """ -Account_Activity models for the X API. +account activity models for the X API. -This module provides models for the Account_Activity endpoints of the X API. +This module provides models for the account activity endpoints of the X API. """ from typing import Dict, List, Optional, Any, Union, Literal @@ -9,13 +9,13 @@ from datetime import datetime -# Models for getAccountActivitySubscriptions +# Models for get_subscriptions -class GetAccountActivitySubscriptionsResponse(BaseModel): - """Response model for getAccountActivitySubscriptions""" +class GetSubscriptionsResponse(BaseModel): + """Response model for get_subscriptions""" - data: Optional["GetAccountActivitySubscriptionsResponseData"] = Field( + data: Optional["GetSubscriptionsResponseData"] = Field( description="The list of active subscriptions for a specified webhook", default_factory=dict, ) @@ -24,8 +24,8 @@ class GetAccountActivitySubscriptionsResponse(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetAccountActivitySubscriptionsResponseData(BaseModel): - """Nested model for GetAccountActivitySubscriptionsResponseData""" +class GetSubscriptionsResponseData(BaseModel): + """Nested model for GetSubscriptionsResponseData""" application_id: Optional[str] = None subscriptions: Optional[List] = None @@ -35,77 +35,77 @@ class GetAccountActivitySubscriptionsResponseData(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for validateAccountActivitySubscription +# Models for validate_subscription -class ValidateAccountActivitySubscriptionResponse(BaseModel): - """Response model for validateAccountActivitySubscription""" +class ValidateSubscriptionResponse(BaseModel): + """Response model for validate_subscription""" - data: Optional["ValidateAccountActivitySubscriptionResponseData"] = None + data: Optional["ValidateSubscriptionResponseData"] = None errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class ValidateAccountActivitySubscriptionResponseData(BaseModel): - """Nested model for ValidateAccountActivitySubscriptionResponseData""" +class ValidateSubscriptionResponseData(BaseModel): + """Nested model for ValidateSubscriptionResponseData""" subscribed: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -# Models for getAccountActivitySubscriptionCount +# Models for delete_subscription -class GetAccountActivitySubscriptionCountResponse(BaseModel): - """Response model for getAccountActivitySubscriptionCount""" +class DeleteSubscriptionResponse(BaseModel): + """Response model for delete_subscription""" - data: Optional["GetAccountActivitySubscriptionCountResponseData"] = Field( - description="The count of active subscriptions across all webhooks", - default_factory=dict, - ) + data: Optional["DeleteSubscriptionResponseData"] = None errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class GetAccountActivitySubscriptionCountResponseData(BaseModel): - """Nested model for GetAccountActivitySubscriptionCountResponseData""" +class DeleteSubscriptionResponseData(BaseModel): + """Nested model for DeleteSubscriptionResponseData""" - account_name: Optional[str] = None - provisioned_count: Optional[str] = None - subscriptions_count_all: Optional[str] = None - subscriptions_count_direct_messages: Optional[str] = None + subscribed: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -# Models for deleteAccountActivitySubscription +# Models for get_subscription_count -class DeleteAccountActivitySubscriptionResponse(BaseModel): - """Response model for deleteAccountActivitySubscription""" +class GetSubscriptionCountResponse(BaseModel): + """Response model for get_subscription_count""" - data: Optional["DeleteAccountActivitySubscriptionResponseData"] = None + data: Optional["GetSubscriptionCountResponseData"] = Field( + description="The count of active subscriptions across all webhooks", + default_factory=dict, + ) errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class DeleteAccountActivitySubscriptionResponseData(BaseModel): - """Nested model for DeleteAccountActivitySubscriptionResponseData""" +class GetSubscriptionCountResponseData(BaseModel): + """Nested model for GetSubscriptionCountResponseData""" - subscribed: Optional[bool] = None + account_name: Optional[str] = None + provisioned_count: Optional[str] = None + subscriptions_count_all: Optional[str] = None + subscriptions_count_direct_messages: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -# Models for createAccountActivityReplayJob +# Models for create_replay_job -class CreateAccountActivityReplayJobResponse(BaseModel): - """Response model for createAccountActivityReplayJob""" +class CreateReplayJobResponse(BaseModel): + """Response model for create_replay_job""" created_at: Optional[str] = None job_id: Optional[str] = None diff --git a/xdk/python/xdk/bookmarks/__init__.py b/xdk/python/xdk/bookmarks/__init__.py index 17ca7bbc..ab7039c6 100644 --- a/xdk/python/xdk/bookmarks/__init__.py +++ b/xdk/python/xdk/bookmarks/__init__.py @@ -1,7 +1,7 @@ """ -Bookmarks module for the X API. +bookmarks module for the X API. -This module provides access to the Bookmarks endpoints of the X API. +This module provides access to the bookmarks endpoints of the X API. """ from .client import BookmarksClient diff --git a/xdk/python/xdk/bookmarks/client.py b/xdk/python/xdk/bookmarks/client.py index 503f5d61..dc74d01b 100644 --- a/xdk/python/xdk/bookmarks/client.py +++ b/xdk/python/xdk/bookmarks/client.py @@ -1,7 +1,7 @@ """ -Bookmarks client for the X API. +bookmarks client for the X API. -This module provides a client for interacting with the Bookmarks endpoints of the X API. +This module provides a client for interacting with the bookmarks endpoints of the X API. """ from __future__ import annotations @@ -12,47 +12,52 @@ if TYPE_CHECKING: from ..client import Client from .models import ( - GetUsersBookmarksByFolderIdResponse, - GetUsersBookmarksResponse, + GetUsersBookmarkFoldersResponse, + GetUsersByFolderIdResponse, CreateUsersBookmarkRequest, CreateUsersBookmarkResponse, DeleteUsersBookmarkResponse, - GetUsersBookmarkFoldersResponse, ) class BookmarksClient: - """Client for Bookmarks operations""" + """Client for bookmarks operations""" def __init__(self, client: Client): self.client = client - def get_users_bookmarks_by_folder_id( + def get_users_bookmark_folders( self, - id: str, - folder_id: str, - ) -> GetUsersBookmarksByFolderIdResponse: + id: Any, + max_results: int = None, + pagination_token: Any = None, + ) -> GetUsersBookmarkFoldersResponse: """ - Get Bookmarks by folder ID - Retrieves Posts in a specific Bookmark folder by its ID for the authenticated user. + Get Bookmark folders + Retrieves a list of Bookmark folders created by the authenticated user. Args: id: The ID of the authenticated source User for whom to return results. Args: - folder_id: The ID of the Bookmark Folder that the authenticated User is trying to fetch Posts for. + max_results: The maximum number of results. + Args: + pagination_token: This parameter is used to get the next 'page' of results. Returns: - GetUsersBookmarksByFolderIdResponse: Response data + GetUsersBookmarkFoldersResponse: Response data """ - url = self.client.base_url + "/2/users/{id}/bookmarks/folders/{folder_id}" + url = self.client.base_url + "/2/users/{id}/bookmarks/folders" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} + if max_results is not None: + params["max_results"] = max_results + if pagination_token is not None: + params["pagination_token"] = pagination_token url = url.replace("{id}", str(id)) - url = url.replace("{folder_id}", str(folder_id)) headers = {} # Make the request if self.client.oauth2_session: @@ -72,69 +77,33 @@ def get_users_bookmarks_by_folder_id( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetUsersBookmarksByFolderIdResponse.model_validate(response_data) + return GetUsersBookmarkFoldersResponse.model_validate(response_data) - def get_users_bookmarks( + def get_users_by_folder_id( self, - id: str, - max_results: int = None, - pagination_token: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetUsersBookmarksResponse: + id: Any, + folder_id: Any, + ) -> GetUsersByFolderIdResponse: """ - Get Bookmarks - Retrieves a list of Posts bookmarked by the authenticated user. + Get Bookmarks by folder ID + Retrieves Posts in a specific Bookmark folder by its ID for the authenticated user. Args: id: The ID of the authenticated source User for whom to return results. Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. + folder_id: The ID of the Bookmark Folder that the authenticated User is trying to fetch Posts for. Returns: - GetUsersBookmarksResponse: Response data + GetUsersByFolderIdResponse: Response data """ - url = self.client.base_url + "/2/users/{id}/bookmarks" + url = self.client.base_url + "/2/users/{id}/bookmarks/folders/{folder_id}" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) url = url.replace("{id}", str(id)) + url = url.replace("{folder_id}", str(folder_id)) headers = {} # Make the request if self.client.oauth2_session: @@ -154,12 +123,12 @@ def get_users_bookmarks( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetUsersBookmarksResponse.model_validate(response_data) + return GetUsersByFolderIdResponse.model_validate(response_data) def create_users_bookmark( self, - id: str, + id: Any, body: CreateUsersBookmarkRequest, ) -> CreateUsersBookmarkResponse: """ @@ -206,8 +175,8 @@ def create_users_bookmark( def delete_users_bookmark( self, - id: str, - tweet_id: str, + id: Any, + tweet_id: Any, ) -> DeleteUsersBookmarkResponse: """ Delete Bookmark @@ -248,55 +217,3 @@ def delete_users_bookmark( response_data = response.json() # Convert to Pydantic model if applicable return DeleteUsersBookmarkResponse.model_validate(response_data) - - - def get_users_bookmark_folders( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - ) -> GetUsersBookmarkFoldersResponse: - """ - Get Bookmark folders - Retrieves a list of Bookmark folders created by the authenticated user. - Args: - id: The ID of the authenticated source User for whom to return results. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Returns: - GetUsersBookmarkFoldersResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/bookmarks/folders" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetUsersBookmarkFoldersResponse.model_validate(response_data) diff --git a/xdk/python/xdk/bookmarks/models.py b/xdk/python/xdk/bookmarks/models.py index 7c33ed74..c29204ee 100644 --- a/xdk/python/xdk/bookmarks/models.py +++ b/xdk/python/xdk/bookmarks/models.py @@ -1,7 +1,7 @@ """ -Bookmarks models for the X API. +bookmarks models for the X API. -This module provides models for the Bookmarks endpoints of the X API. +This module provides models for the bookmarks endpoints of the X API. """ from typing import Dict, List, Optional, Any, Union, Literal @@ -9,67 +9,53 @@ from datetime import datetime -# Models for getUsersBookmarksByFolderId +# Models for get_users_bookmark_folders -class GetUsersBookmarksByFolderIdResponse(BaseModel): - """Response model for getUsersBookmarksByFolderId""" +class GetUsersBookmarkFoldersResponse(BaseModel): + """Response model for get_users_bookmark_folders""" - data: Optional["GetUsersBookmarksByFolderIdResponseData"] = None + data: Optional[List] = None + errors: Optional[List] = None + meta: Optional["GetUsersBookmarkFoldersResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersBookmarksByFolderIdResponseData(BaseModel): - """Nested model for GetUsersBookmarksByFolderIdResponseData""" +class GetUsersBookmarkFoldersResponseMeta(BaseModel): + """Nested model for GetUsersBookmarkFoldersResponseMeta""" - id: Optional[str] = None + pagination_token: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -# Models for getUsersBookmarks +# Models for get_users_by_folder_id -class GetUsersBookmarksResponse(BaseModel): - """Response model for getUsersBookmarks""" +class GetUsersByFolderIdResponse(BaseModel): + """Response model for get_users_by_folder_id""" data: Optional[List] = None errors: Optional[List] = None - includes: Optional["GetUsersBookmarksResponseIncludes"] = None - meta: Optional["GetUsersBookmarksResponseMeta"] = None + meta: Optional["GetUsersByFolderIdResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersBookmarksResponseIncludes(BaseModel): - """Nested model for GetUsersBookmarksResponseIncludes""" +class GetUsersByFolderIdResponseMeta(BaseModel): + """Nested model for GetUsersByFolderIdResponseMeta""" - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None + pagination_token: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersBookmarksResponseMeta(BaseModel): - """Nested model for GetUsersBookmarksResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for createUsersBookmark +# Models for create_users_bookmark class CreateUsersBookmarkRequest(BaseModel): - """Request model for createUsersBookmark""" + """Request model for create_users_bookmark""" tweet_id: Optional[str] = None @@ -77,7 +63,7 @@ class CreateUsersBookmarkRequest(BaseModel): class CreateUsersBookmarkResponse(BaseModel): - """Response model for createUsersBookmark""" + """Response model for create_users_bookmark""" data: Optional["CreateUsersBookmarkResponseData"] = None errors: Optional[List] = None @@ -93,11 +79,11 @@ class CreateUsersBookmarkResponseData(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for deleteUsersBookmark +# Models for delete_users_bookmark class DeleteUsersBookmarkResponse(BaseModel): - """Response model for deleteUsersBookmark""" + """Response model for delete_users_bookmark""" data: Optional["DeleteUsersBookmarkResponseData"] = None errors: Optional[List] = None @@ -111,23 +97,3 @@ class DeleteUsersBookmarkResponseData(BaseModel): bookmarked: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) - - -# Models for getUsersBookmarkFolders - - -class GetUsersBookmarkFoldersResponse(BaseModel): - """Response model for getUsersBookmarkFolders""" - - data: Optional["GetUsersBookmarkFoldersResponseData"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetUsersBookmarkFoldersResponseData(BaseModel): - """Nested model for GetUsersBookmarkFoldersResponseData""" - - id: Optional[str] = None - name: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) diff --git a/xdk/python/xdk/client.py b/xdk/python/xdk/client.py index cade5766..39d3527f 100644 --- a/xdk/python/xdk/client.py +++ b/xdk/python/xdk/client.py @@ -10,43 +10,41 @@ from .oauth2_auth import OAuth2PKCEAuth from .paginator import Cursor, cursor, PaginationError -from .connection.client import ConnectionClient - -from .spaces.client import SpacesClient - from .stream.client import StreamClient -from .community_notes.client import CommunityNotesClient - from .direct_messages.client import DirectMessagesClient -from .compliance.client import ComplianceClient +from .communities.client import CommunitiesClient + +from .connection.client import ConnectionClient + +from .general.client import GeneralClient from .webhooks.client import WebhooksClient -from .tweets.client import TweetsClient +from .posts.client import PostsClient from .media.client import MediaClient -from .likes.client import LikesClient +from .compliance.client import ComplianceClient -from .aaasubscriptions.client import AAASubscriptionsClient +from .users.client import UsersClient -from .account_activity.client import AccountActivityClient +from .spaces.client import SpacesClient -from .usage.client import UsageClient +from .community_notes.client import CommunityNotesClient -from .users.client import UsersClient +from .aaasubscriptions.client import AaasubscriptionsClient -from .communities.client import CommunitiesClient +from .lists.client import ListsClient -from .bookmarks.client import BookmarksClient +from .trends.client import TrendsClient -from .lists.client import ListsClient +from .bookmarks.client import BookmarksClient -from .general.client import GeneralClient +from .usage.client import UsageClient -from .trends.client import TrendsClient +from .account_activity.client import AccountActivityClient class Client: @@ -88,25 +86,24 @@ def __init__( scope=scope, ) # Initialize clients for each tag - self.connection = ConnectionClient(self) - self.spaces = SpacesClient(self) self.stream = StreamClient(self) - self.community_notes = CommunityNotesClient(self) self.direct_messages = DirectMessagesClient(self) - self.compliance = ComplianceClient(self) + self.communities = CommunitiesClient(self) + self.connection = ConnectionClient(self) + self.general = GeneralClient(self) self.webhooks = WebhooksClient(self) - self.tweets = TweetsClient(self) + self.posts = PostsClient(self) self.media = MediaClient(self) - self.likes = LikesClient(self) - self.aaasubscriptions = AAASubscriptionsClient(self) - self.account_activity = AccountActivityClient(self) - self.usage = UsageClient(self) + self.compliance = ComplianceClient(self) self.users = UsersClient(self) - self.communities = CommunitiesClient(self) - self.bookmarks = BookmarksClient(self) + self.spaces = SpacesClient(self) + self.community_notes = CommunityNotesClient(self) + self.aaasubscriptions = AaasubscriptionsClient(self) self.lists = ListsClient(self) - self.general = GeneralClient(self) self.trends = TrendsClient(self) + self.bookmarks = BookmarksClient(self) + self.usage = UsageClient(self) + self.account_activity = AccountActivityClient(self) @property diff --git a/xdk/python/xdk/communities/__init__.py b/xdk/python/xdk/communities/__init__.py index be73767a..125a4e73 100644 --- a/xdk/python/xdk/communities/__init__.py +++ b/xdk/python/xdk/communities/__init__.py @@ -1,7 +1,7 @@ """ -Communities module for the X API. +communities module for the X API. -This module provides access to the Communities endpoints of the X API. +This module provides access to the communities endpoints of the X API. """ from .client import CommunitiesClient diff --git a/xdk/python/xdk/communities/client.py b/xdk/python/xdk/communities/client.py index 1fce6de5..df250177 100644 --- a/xdk/python/xdk/communities/client.py +++ b/xdk/python/xdk/communities/client.py @@ -1,7 +1,7 @@ """ -Communities client for the X API. +communities client for the X API. -This module provides a client for interacting with the Communities endpoints of the X API. +This module provides a client for interacting with the communities endpoints of the X API. """ from __future__ import annotations @@ -12,27 +12,69 @@ if TYPE_CHECKING: from ..client import Client from .models import ( - SearchCommunitiesResponse, - GetCommunitiesByIdResponse, + GetByIdResponse, + SearchResponse, ) class CommunitiesClient: - """Client for Communities operations""" + """Client for communities operations""" def __init__(self, client: Client): self.client = client - def search_communities( + def get_by_id( + self, + id: Any, + ) -> GetByIdResponse: + """ + Get Community by ID + Retrieves details of a specific Community by its ID. + Args: + id: The ID of the Community. + Returns: + GetByIdResponse: Response data + """ + url = self.client.base_url + "/2/communities/{id}" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + url = url.replace("{id}", str(id)) + headers = {} + # Make the request + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetByIdResponse.model_validate(response_data) + + + def search( self, query: str, max_results: int = None, - next_token: str = None, - pagination_token: str = None, - community_fields: List = None, - ) -> SearchCommunitiesResponse: + next_token: Any = None, + pagination_token: Any = None, + ) -> SearchResponse: """ Search Communities Retrieves a list of Communities matching the specified search query. @@ -44,10 +86,8 @@ def search_communities( next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. Args: pagination_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - community_fields: A comma separated list of Community fields to display. Returns: - SearchCommunitiesResponse: Response data + SearchResponse: Response data """ url = self.client.base_url + "/2/communities/search" # Ensure we have a valid access token @@ -64,10 +104,6 @@ def search_communities( params["next_token"] = next_token if pagination_token is not None: params["pagination_token"] = pagination_token - if community_fields is not None: - params["community.fields"] = ",".join( - str(item) for item in community_fields - ) headers = {} # Make the request if self.client.oauth2_session: @@ -87,54 +123,4 @@ def search_communities( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return SearchCommunitiesResponse.model_validate(response_data) - - - def get_communities_by_id( - self, - id: str, - community_fields: List = None, - ) -> GetCommunitiesByIdResponse: - """ - Get Community by ID - Retrieves details of a specific Community by its ID. - Args: - id: The ID of the Community. - Args: - community_fields: A comma separated list of Community fields to display. - Returns: - GetCommunitiesByIdResponse: Response data - """ - url = self.client.base_url + "/2/communities/{id}" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if community_fields is not None: - params["community.fields"] = ",".join( - str(item) for item in community_fields - ) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetCommunitiesByIdResponse.model_validate(response_data) + return SearchResponse.model_validate(response_data) diff --git a/xdk/python/xdk/communities/models.py b/xdk/python/xdk/communities/models.py index ba80afc1..d4cc8ab4 100644 --- a/xdk/python/xdk/communities/models.py +++ b/xdk/python/xdk/communities/models.py @@ -1,7 +1,7 @@ """ -Communities models for the X API. +communities models for the X API. -This module provides models for the Communities endpoints of the X API. +This module provides models for the communities endpoints of the X API. """ from typing import Dict, List, Optional, Any, Union, Literal @@ -9,46 +9,46 @@ from datetime import datetime -# Models for searchCommunities +# Models for get_by_id -class SearchCommunitiesResponse(BaseModel): - """Response model for searchCommunities""" +class GetByIdResponse(BaseModel): + """Response model for get_by_id""" - data: Optional[List] = None + data: Optional["GetByIdResponseData"] = Field( + description="A X Community is a curated group of Posts.", default_factory=dict + ) errors: Optional[List] = None - meta: Optional["SearchCommunitiesResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class SearchCommunitiesResponseMeta(BaseModel): - """Nested model for SearchCommunitiesResponseMeta""" +class GetByIdResponseData(BaseModel): + """Nested model for GetByIdResponseData""" - next_token: Optional[str] = None + created_at: Optional[str] = None + id: Optional[str] = None + name: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -# Models for getCommunitiesById +# Models for search -class GetCommunitiesByIdResponse(BaseModel): - """Response model for getCommunitiesById""" +class SearchResponse(BaseModel): + """Response model for search""" - data: Optional["GetCommunitiesByIdResponseData"] = Field( - description="A X Community is a curated group of Posts.", default_factory=dict - ) + data: Optional[List] = None errors: Optional[List] = None + meta: Optional["SearchResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetCommunitiesByIdResponseData(BaseModel): - """Nested model for GetCommunitiesByIdResponseData""" +class SearchResponseMeta(BaseModel): + """Nested model for SearchResponseMeta""" - created_at: Optional[str] = None - id: Optional[str] = None - name: Optional[str] = None + next_token: Optional[str] = None model_config = ConfigDict(populate_by_name=True) diff --git a/xdk/python/xdk/community_notes/__init__.py b/xdk/python/xdk/community_notes/__init__.py index 12ffe09f..4cb2b7ac 100644 --- a/xdk/python/xdk/community_notes/__init__.py +++ b/xdk/python/xdk/community_notes/__init__.py @@ -1,7 +1,7 @@ """ -Community_Notes module for the X API. +community notes module for the X API. -This module provides access to the Community_Notes endpoints of the X API. +This module provides access to the community notes endpoints of the X API. """ from .client import CommunityNotesClient diff --git a/xdk/python/xdk/community_notes/client.py b/xdk/python/xdk/community_notes/client.py index ec8cce8b..74db4e15 100644 --- a/xdk/python/xdk/community_notes/client.py +++ b/xdk/python/xdk/community_notes/client.py @@ -1,7 +1,7 @@ """ -Community_Notes client for the X API. +community notes client for the X API. -This module provides a client for interacting with the Community_Notes endpoints of the X API. +This module provides a client for interacting with the community notes endpoints of the X API. """ from __future__ import annotations @@ -12,114 +12,124 @@ if TYPE_CHECKING: from ..client import Client from .models import ( - CreateNotesRequest, - CreateNotesResponse, - DeleteNotesResponse, - SearchNotesWrittenResponse, - SearchForEligiblePostsResponse, + SearchEligiblePostsResponse, + CreateRequest, + CreateResponse, + SearchWrittenResponse, + DeleteResponse, ) class CommunityNotesClient: - """Client for Community_Notes operations""" + """Client for community notes operations""" def __init__(self, client: Client): self.client = client - def create_notes( + def search_eligible_posts( self, - body: Optional[CreateNotesRequest] = None, - ) -> CreateNotesResponse: + test_mode: bool, + pagination_token: str = None, + max_results: int = None, + ) -> SearchEligiblePostsResponse: """ - Create a Community Note - Creates a community note endpoint for LLM use case. - body: Request body + Search for Posts Eligible for Community Notes + Returns all the posts that are eligible for community notes. + Args: + test_mode: If true, return a list of posts that are for the test. If false, return a list of posts that the bots can write proposed notes on the product. + Args: + pagination_token: Pagination token to get next set of posts eligible for notes. + Args: + max_results: Max results to return. Returns: - CreateNotesResponse: Response data + SearchEligiblePostsResponse: Response data """ - url = self.client.base_url + "/2/notes" + url = self.client.base_url + "/2/notes/search/posts_eligible_for_notes" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} + if test_mode is not None: + params["test_mode"] = test_mode + if pagination_token is not None: + params["pagination_token"] = pagination_token + if max_results is not None: + params["max_results"] = max_results headers = {} - headers["Content-Type"] = "application/json" # Make the request if self.client.oauth2_session: - response = self.client.oauth2_session.post( + response = self.client.oauth2_session.get( url, params=params, headers=headers, - json=body.model_dump(exclude_none=True) if body else None, ) else: - response = self.client.session.post( + response = self.client.session.get( url, params=params, headers=headers, - json=body.model_dump(exclude_none=True) if body else None, ) # Check for errors response.raise_for_status() # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return CreateNotesResponse.model_validate(response_data) + return SearchEligiblePostsResponse.model_validate(response_data) - def delete_notes( + def create( self, - id: str, - ) -> DeleteNotesResponse: + body: Optional[CreateRequest] = None, + ) -> CreateResponse: """ - Delete a Community Note - Deletes a community note. - Args: - id: The community note id to delete. + Create a Community Note + Creates a community note endpoint for LLM use case. + body: Request body Returns: - DeleteNotesResponse: Response data + CreateResponse: Response data """ - url = self.client.base_url + "/2/notes/{id}" + url = self.client.base_url + "/2/notes" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} - url = url.replace("{id}", str(id)) headers = {} + headers["Content-Type"] = "application/json" # Make the request if self.client.oauth2_session: - response = self.client.oauth2_session.delete( + response = self.client.oauth2_session.post( url, params=params, headers=headers, + json=body.model_dump(exclude_none=True) if body else None, ) else: - response = self.client.session.delete( + response = self.client.session.post( url, params=params, headers=headers, + json=body.model_dump(exclude_none=True) if body else None, ) # Check for errors response.raise_for_status() # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return DeleteNotesResponse.model_validate(response_data) + return CreateResponse.model_validate(response_data) - def search_notes_written( + def search_written( self, test_mode: bool, pagination_token: str = None, max_results: int = None, - note_fields: List = None, - ) -> SearchNotesWrittenResponse: + ) -> SearchWrittenResponse: """ Search for Community Notes Written Returns all the community notes written by the user. @@ -129,10 +139,8 @@ def search_notes_written( pagination_token: Pagination token to get next set of posts eligible for notes. Args: max_results: Max results to return. - Args: - note_fields: A comma separated list of Note fields to display. Returns: - SearchNotesWrittenResponse: Response data + SearchWrittenResponse: Response data """ url = self.client.base_url + "/2/notes/search/notes_written" # Ensure we have a valid access token @@ -147,8 +155,6 @@ def search_notes_written( params["pagination_token"] = pagination_token if max_results is not None: params["max_results"] = max_results - if note_fields is not None: - params["note.fields"] = ",".join(str(item) for item in note_fields) headers = {} # Make the request if self.client.oauth2_session: @@ -168,80 +174,39 @@ def search_notes_written( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return SearchNotesWrittenResponse.model_validate(response_data) + return SearchWrittenResponse.model_validate(response_data) - def search_for_eligible_posts( + def delete( self, - test_mode: bool, - pagination_token: str = None, - max_results: int = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> SearchForEligiblePostsResponse: + id: Any, + ) -> DeleteResponse: """ - Search for Posts Eligible for Community Notes - Returns all the posts that are eligible for community notes. - Args: - test_mode: If true, return a list of posts that are for the test. If false, return a list of posts that the bots can write proposed notes on the product. - Args: - pagination_token: Pagination token to get next set of posts eligible for notes. - Args: - max_results: Max results to return. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. + Delete a Community Note + Deletes a community note. Args: - place_fields: A comma separated list of Place fields to display. + id: The community note id to delete. Returns: - SearchForEligiblePostsResponse: Response data + DeleteResponse: Response data """ - url = self.client.base_url + "/2/notes/search/posts_eligible_for_notes" + url = self.client.base_url + "/2/notes/{id}" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} - if test_mode is not None: - params["test_mode"] = test_mode - if pagination_token is not None: - params["pagination_token"] = pagination_token - if max_results is not None: - params["max_results"] = max_results - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) + url = url.replace("{id}", str(id)) headers = {} # Make the request if self.client.oauth2_session: - response = self.client.oauth2_session.get( + response = self.client.oauth2_session.delete( url, params=params, headers=headers, ) else: - response = self.client.session.get( + response = self.client.session.delete( url, params=params, headers=headers, @@ -251,4 +216,4 @@ def search_for_eligible_posts( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return SearchForEligiblePostsResponse.model_validate(response_data) + return DeleteResponse.model_validate(response_data) diff --git a/xdk/python/xdk/community_notes/models.py b/xdk/python/xdk/community_notes/models.py index 26e21389..3f73d7fa 100644 --- a/xdk/python/xdk/community_notes/models.py +++ b/xdk/python/xdk/community_notes/models.py @@ -1,7 +1,7 @@ """ -Community_Notes models for the X API. +community notes models for the X API. -This module provides models for the Community_Notes endpoints of the X API. +This module provides models for the community notes endpoints of the X API. """ from typing import Dict, List, Optional, Any, Union, Literal @@ -9,84 +9,100 @@ from datetime import datetime -# Models for createNotes +# Models for search_eligible_posts -class CreateNotesRequest(BaseModel): - """Request model for createNotes""" +class SearchEligiblePostsResponse(BaseModel): + """Response model for search_eligible_posts""" - info: Optional["CreateNotesRequestInfo"] = Field( - description="A X Community Note is a note on a Post.", default_factory=dict - ) - post_id: Optional[str] = None - test_mode: Optional[bool] = None + data: Optional[List] = None + errors: Optional[List] = None + includes: Optional["SearchEligiblePostsResponseIncludes"] = None + meta: Optional["SearchEligiblePostsResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class CreateNotesResponse(BaseModel): - """Response model for createNotes""" +class SearchEligiblePostsResponseIncludes(BaseModel): + """Nested model for SearchEligiblePostsResponseIncludes""" - data: Optional["CreateNotesResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class CreateNotesRequestInfo(BaseModel): - """Nested model for CreateNotesRequestInfo""" +class SearchEligiblePostsResponseMeta(BaseModel): + """Nested model for SearchEligiblePostsResponseMeta""" - classification: Optional[str] = None - misleading_tags: Optional[List] = None - text: Optional[str] = None - trustworthy_sources: Optional[bool] = None + next_token: Optional[str] = None + result_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class CreateNotesResponseData(BaseModel): - """Nested model for CreateNotesResponseData""" +# Models for create - deleted: Optional[bool] = None - model_config = ConfigDict(populate_by_name=True) +class CreateRequest(BaseModel): + """Request model for create""" + info: Optional["CreateRequestInfo"] = Field( + description="A X Community Note is a note on a Post.", default_factory=dict + ) + post_id: Optional[str] = None + test_mode: Optional[bool] = None -# Models for deleteNotes + model_config = ConfigDict(populate_by_name=True) -class DeleteNotesResponse(BaseModel): - """Response model for deleteNotes""" +class CreateResponse(BaseModel): + """Response model for create""" - data: Optional["DeleteNotesResponseData"] = None + data: Optional["CreateResponseData"] = Field(default_factory=dict) errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class DeleteNotesResponseData(BaseModel): - """Nested model for DeleteNotesResponseData""" +class CreateRequestInfo(BaseModel): + """Nested model for CreateRequestInfo""" - id: Optional[str] = None + classification: Optional[str] = None + misleading_tags: Optional[List] = None + text: Optional[str] = None + trustworthy_sources: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -# Models for searchNotesWritten +class CreateResponseData(BaseModel): + """Nested model for CreateResponseData""" + deleted: Optional[bool] = None -class SearchNotesWrittenResponse(BaseModel): - """Response model for searchNotesWritten""" + model_config = ConfigDict(populate_by_name=True) + + +# Models for search_written + + +class SearchWrittenResponse(BaseModel): + """Response model for search_written""" data: Optional[List] = None errors: Optional[List] = None - meta: Optional["SearchNotesWrittenResponseMeta"] = None + meta: Optional["SearchWrittenResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class SearchNotesWrittenResponseMeta(BaseModel): - """Nested model for SearchNotesWrittenResponseMeta""" +class SearchWrittenResponseMeta(BaseModel): + """Nested model for SearchWrittenResponseMeta""" next_token: Optional[str] = None result_count: Optional[int] = None @@ -94,37 +110,21 @@ class SearchNotesWrittenResponseMeta(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for searchForEligiblePosts +# Models for delete -class SearchForEligiblePostsResponse(BaseModel): - """Response model for searchForEligiblePosts""" +class DeleteResponse(BaseModel): + """Response model for delete""" - data: Optional[List] = None + data: Optional["DeleteResponseData"] = None errors: Optional[List] = None - includes: Optional["SearchForEligiblePostsResponseIncludes"] = None - meta: Optional["SearchForEligiblePostsResponseMeta"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class SearchForEligiblePostsResponseIncludes(BaseModel): - """Nested model for SearchForEligiblePostsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class SearchForEligiblePostsResponseMeta(BaseModel): - """Nested model for SearchForEligiblePostsResponseMeta""" +class DeleteResponseData(BaseModel): + """Nested model for DeleteResponseData""" - next_token: Optional[str] = None - result_count: Optional[int] = None + id: Optional[str] = None model_config = ConfigDict(populate_by_name=True) diff --git a/xdk/python/xdk/compliance/__init__.py b/xdk/python/xdk/compliance/__init__.py index afc20103..5fd46443 100644 --- a/xdk/python/xdk/compliance/__init__.py +++ b/xdk/python/xdk/compliance/__init__.py @@ -1,7 +1,7 @@ """ -Compliance module for the X API. +compliance module for the X API. -This module provides access to the Compliance endpoints of the X API. +This module provides access to the compliance endpoints of the X API. """ from .client import ComplianceClient diff --git a/xdk/python/xdk/compliance/client.py b/xdk/python/xdk/compliance/client.py index 7cb665d3..c8a8c00b 100644 --- a/xdk/python/xdk/compliance/client.py +++ b/xdk/python/xdk/compliance/client.py @@ -1,7 +1,7 @@ """ -Compliance client for the X API. +compliance client for the X API. -This module provides a client for interacting with the Compliance endpoints of the X API. +This module provides a client for interacting with the compliance endpoints of the X API. """ from __future__ import annotations @@ -12,39 +12,32 @@ if TYPE_CHECKING: from ..client import Client from .models import ( - GetComplianceJobsByIdResponse, - StreamLikesComplianceResponse, - StreamPostsComplianceResponse, - GetComplianceJobsResponse, - CreateComplianceJobsRequest, - CreateComplianceJobsResponse, - StreamUsersComplianceResponse, - StreamLabelsComplianceResponse, + GetJobsByIdResponse, + GetJobsResponse, + CreateJobsRequest, + CreateJobsResponse, ) class ComplianceClient: - """Client for Compliance operations""" + """Client for compliance operations""" def __init__(self, client: Client): self.client = client - def get_compliance_jobs_by_id( + def get_jobs_by_id( self, - id: str, - compliance_job_fields: List = None, - ) -> GetComplianceJobsByIdResponse: + id: Any, + ) -> GetJobsByIdResponse: """ Get Compliance Job by ID Retrieves details of a specific Compliance Job by its ID. Args: id: The ID of the Compliance Job to retrieve. - Args: - compliance_job_fields: A comma separated list of ComplianceJob fields to display. Returns: - GetComplianceJobsByIdResponse: Response data + GetJobsByIdResponse: Response data """ url = self.client.base_url + "/2/compliance/jobs/{id}" if self.client.bearer_token: @@ -56,10 +49,6 @@ def get_compliance_jobs_by_id( f"Bearer {self.client.access_token}" ) params = {} - if compliance_job_fields is not None: - params["compliance_job.fields"] = ",".join( - str(item) for item in compliance_job_fields - ) url = url.replace("{id}", str(id)) headers = {} # Make the request @@ -73,118 +62,14 @@ def get_compliance_jobs_by_id( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetComplianceJobsByIdResponse.model_validate(response_data) - - - def stream_likes_compliance( - self, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - ) -> StreamLikesComplianceResponse: - """ - Stream Likes compliance data - Streams all compliance data related to Likes for Users. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Likes Compliance events will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp from which the Likes Compliance events will be provided. - Returns: - StreamLikesComplianceResponse: Response data - """ - url = self.client.base_url + "/2/likes/compliance/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamLikesComplianceResponse.model_validate(response_data) - - - def stream_posts_compliance( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - ) -> StreamPostsComplianceResponse: - """ - Stream Posts compliance data - Streams all compliance data related to Posts. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Post Compliance events will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Post Compliance events will be provided. - Returns: - StreamPostsComplianceResponse: Response data - """ - url = self.client.base_url + "/2/tweets/compliance/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamPostsComplianceResponse.model_validate(response_data) + return GetJobsByIdResponse.model_validate(response_data) - def get_compliance_jobs( + def get_jobs( self, type: str, status: str = None, - compliance_job_fields: List = None, - ) -> GetComplianceJobsResponse: + ) -> GetJobsResponse: """ Get Compliance Jobs Retrieves a list of Compliance Jobs filtered by job type and optional status. @@ -192,10 +77,8 @@ def get_compliance_jobs( type: Type of Compliance Job to list. Args: status: Status of Compliance Job to list. - Args: - compliance_job_fields: A comma separated list of ComplianceJob fields to display. Returns: - GetComplianceJobsResponse: Response data + GetJobsResponse: Response data """ url = self.client.base_url + "/2/compliance/jobs" if self.client.bearer_token: @@ -211,10 +94,6 @@ def get_compliance_jobs( params["type"] = type if status is not None: params["status"] = status - if compliance_job_fields is not None: - params["compliance_job.fields"] = ",".join( - str(item) for item in compliance_job_fields - ) headers = {} # Make the request response = self.client.session.get( @@ -227,19 +106,19 @@ def get_compliance_jobs( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetComplianceJobsResponse.model_validate(response_data) + return GetJobsResponse.model_validate(response_data) - def create_compliance_jobs( + def create_jobs( self, - body: CreateComplianceJobsRequest, - ) -> CreateComplianceJobsResponse: + body: CreateJobsRequest, + ) -> CreateJobsResponse: """ Create Compliance Job Creates a new Compliance Job for the specified job type. body: A request to create a new batch compliance job. Returns: - CreateComplianceJobsResponse: Response data + CreateJobsResponse: Response data """ url = self.client.base_url + "/2/compliance/jobs" if self.client.bearer_token: @@ -265,107 +144,4 @@ def create_compliance_jobs( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return CreateComplianceJobsResponse.model_validate(response_data) - - - def stream_users_compliance( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - ) -> StreamUsersComplianceResponse: - """ - Stream Users compliance data - Streams all compliance data related to Users. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the User Compliance events will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp from which the User Compliance events will be provided. - Returns: - StreamUsersComplianceResponse: Response data - """ - url = self.client.base_url + "/2/users/compliance/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamUsersComplianceResponse.model_validate(response_data) - - - def stream_labels_compliance( - self, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - ) -> StreamLabelsComplianceResponse: - """ - Stream Post labels - Streams all labeling events applied to Posts. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Post labels will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp from which the Post labels will be provided. - Returns: - StreamLabelsComplianceResponse: Response data - """ - url = self.client.base_url + "/2/tweets/label/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamLabelsComplianceResponse.model_validate(response_data) + return CreateJobsResponse.model_validate(response_data) diff --git a/xdk/python/xdk/compliance/models.py b/xdk/python/xdk/compliance/models.py index a820eb49..a98ada67 100644 --- a/xdk/python/xdk/compliance/models.py +++ b/xdk/python/xdk/compliance/models.py @@ -1,7 +1,7 @@ """ -Compliance models for the X API. +compliance models for the X API. -This module provides models for the Compliance endpoints of the X API. +This module provides models for the compliance endpoints of the X API. """ from typing import Dict, List, Optional, Any, Union, Literal @@ -9,20 +9,20 @@ from datetime import datetime -# Models for getComplianceJobsById +# Models for get_jobs_by_id -class GetComplianceJobsByIdResponse(BaseModel): - """Response model for getComplianceJobsById""" +class GetJobsByIdResponse(BaseModel): + """Response model for get_jobs_by_id""" - data: Optional["GetComplianceJobsByIdResponseData"] = Field(default_factory=dict) + data: Optional["GetJobsByIdResponseData"] = Field(default_factory=dict) errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class GetComplianceJobsByIdResponseData(BaseModel): - """Nested model for GetComplianceJobsByIdResponseData""" +class GetJobsByIdResponseData(BaseModel): + """Nested model for GetJobsByIdResponseData""" created_at: Optional[str] = None download_expires_at: Optional[str] = None @@ -37,56 +37,32 @@ class GetComplianceJobsByIdResponseData(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for streamLikesCompliance +# Models for get_jobs -class StreamLikesComplianceResponse(BaseModel): - """Response model for streamLikesCompliance""" - - data: Optional[Dict[str, Any]] = Field(default=None) - errors: Optional[List] = Field(default=None) - - model_config = ConfigDict(populate_by_name=True) - - -# Models for streamPostsCompliance - - -class StreamPostsComplianceResponse(BaseModel): - """Response model for streamPostsCompliance""" - - data: Optional[Any] = Field(default=None, description="Tweet compliance data.") - errors: Optional[List] = Field(default=None) - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getComplianceJobs - - -class GetComplianceJobsResponse(BaseModel): - """Response model for getComplianceJobs""" +class GetJobsResponse(BaseModel): + """Response model for get_jobs""" data: Optional[List] = None errors: Optional[List] = None - meta: Optional["GetComplianceJobsResponseMeta"] = None + meta: Optional["GetJobsResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetComplianceJobsResponseMeta(BaseModel): - """Nested model for GetComplianceJobsResponseMeta""" +class GetJobsResponseMeta(BaseModel): + """Nested model for GetJobsResponseMeta""" result_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -# Models for createComplianceJobs +# Models for create_jobs -class CreateComplianceJobsRequest(BaseModel): - """Request model for createComplianceJobs""" +class CreateJobsRequest(BaseModel): + """Request model for create_jobs""" name: Optional[str] = None resumable: Optional[bool] = None @@ -95,17 +71,17 @@ class CreateComplianceJobsRequest(BaseModel): model_config = ConfigDict(populate_by_name=True) -class CreateComplianceJobsResponse(BaseModel): - """Response model for createComplianceJobs""" +class CreateJobsResponse(BaseModel): + """Response model for create_jobs""" - data: Optional["CreateComplianceJobsResponseData"] = Field(default_factory=dict) + data: Optional["CreateJobsResponseData"] = Field(default_factory=dict) errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class CreateComplianceJobsResponseData(BaseModel): - """Nested model for CreateComplianceJobsResponseData""" +class CreateJobsResponseData(BaseModel): + """Nested model for CreateJobsResponseData""" created_at: Optional[str] = None download_expires_at: Optional[str] = None @@ -118,27 +94,3 @@ class CreateComplianceJobsResponseData(BaseModel): upload_url: Optional[str] = None model_config = ConfigDict(populate_by_name=True) - - -# Models for streamUsersCompliance - - -class StreamUsersComplianceResponse(BaseModel): - """Response model for streamUsersCompliance""" - - data: Optional[Any] = Field(default=None, description="User compliance data.") - errors: Optional[List] = Field(default=None) - - model_config = ConfigDict(populate_by_name=True) - - -# Models for streamLabelsCompliance - - -class StreamLabelsComplianceResponse(BaseModel): - """Response model for streamLabelsCompliance""" - - data: Optional[Any] = Field(default=None, description="Tweet label data.") - errors: Optional[List] = Field(default=None) - - model_config = ConfigDict(populate_by_name=True) diff --git a/xdk/python/xdk/connection/__init__.py b/xdk/python/xdk/connection/__init__.py index 02192af8..45f03d23 100644 --- a/xdk/python/xdk/connection/__init__.py +++ b/xdk/python/xdk/connection/__init__.py @@ -1,7 +1,7 @@ """ -Connection module for the X API. +connection module for the X API. -This module provides access to the Connection endpoints of the X API. +This module provides access to the connection endpoints of the X API. """ from .client import ConnectionClient diff --git a/xdk/python/xdk/connection/client.py b/xdk/python/xdk/connection/client.py index 9303bb61..30e95281 100644 --- a/xdk/python/xdk/connection/client.py +++ b/xdk/python/xdk/connection/client.py @@ -1,7 +1,7 @@ """ -Connection client for the X API. +connection client for the X API. -This module provides a client for interacting with the Connection endpoints of the X API. +This module provides a client for interacting with the connection endpoints of the X API. """ from __future__ import annotations @@ -17,7 +17,7 @@ class ConnectionClient: - """Client for Connection operations""" + """Client for connection operations""" def __init__(self, client: Client): diff --git a/xdk/python/xdk/connection/models.py b/xdk/python/xdk/connection/models.py index 3ead0b00..be6c749a 100644 --- a/xdk/python/xdk/connection/models.py +++ b/xdk/python/xdk/connection/models.py @@ -1,7 +1,7 @@ """ -Connection models for the X API. +connection models for the X API. -This module provides models for the Connection endpoints of the X API. +This module provides models for the connection endpoints of the X API. """ from typing import Dict, List, Optional, Any, Union, Literal @@ -9,11 +9,11 @@ from datetime import datetime -# Models for deleteAllConnections +# Models for delete_all_connections class DeleteAllConnectionsResponse(BaseModel): - """Response model for deleteAllConnections""" + """Response model for delete_all_connections""" data: Optional["DeleteAllConnectionsResponseData"] = None errors: Optional[List] = None diff --git a/xdk/python/xdk/direct_messages/__init__.py b/xdk/python/xdk/direct_messages/__init__.py index 11c905df..47d7682b 100644 --- a/xdk/python/xdk/direct_messages/__init__.py +++ b/xdk/python/xdk/direct_messages/__init__.py @@ -1,7 +1,7 @@ """ -Direct_Messages module for the X API. +direct messages module for the X API. -This module provides access to the Direct_Messages endpoints of the X API. +This module provides access to the direct messages endpoints of the X API. """ from .client import DirectMessagesClient diff --git a/xdk/python/xdk/direct_messages/client.py b/xdk/python/xdk/direct_messages/client.py index 579aa533..b5817e24 100644 --- a/xdk/python/xdk/direct_messages/client.py +++ b/xdk/python/xdk/direct_messages/client.py @@ -1,7 +1,7 @@ """ -Direct_Messages client for the X API. +direct messages client for the X API. -This module provides a client for interacting with the Direct_Messages endpoints of the X API. +This module provides a client for interacting with the direct messages endpoints of the X API. """ from __future__ import annotations @@ -13,21 +13,21 @@ from ..client import Client from .models import ( GetDmConversationsIdDmEventsResponse, - GetDmEventsByParticipantIdResponse, - GetDmEventsResponse, - GetDmEventsByIdResponse, - DeleteDmEventsResponse, - CreateDmByParticipantIdRequest, - CreateDmByParticipantIdResponse, CreateDmByConversationIdRequest, CreateDmByConversationIdResponse, + GetEventsByIdResponse, + DeleteDmEventsResponse, CreateDmConversationsRequest, CreateDmConversationsResponse, + GetDmEventsByParticipantIdResponse, + GetEventsResponse, + CreateDmByParticipantIdRequest, + CreateDmByParticipantIdResponse, ) class DirectMessagesClient: - """Client for Direct_Messages operations""" + """Client for direct messages operations""" def __init__(self, client: Client): @@ -36,15 +36,10 @@ def __init__(self, client: Client): def get_dm_conversations_id_dm_events( self, - id: str, + id: Any, max_results: int = None, - pagination_token: str = None, + pagination_token: Any = None, event_types: List = None, - dm_event_fields: List = None, - expansions: List = None, - media_fields: List = None, - user_fields: List = None, - tweet_fields: List = None, ) -> GetDmConversationsIdDmEventsResponse: """ Get DM events for a DM conversation @@ -57,16 +52,6 @@ def get_dm_conversations_id_dm_events( pagination_token: This parameter is used to get a specified 'page' of results. Args: event_types: The set of event_types to include in the results. - Args: - dm_event_fields: A comma separated list of DmEvent fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - tweet_fields: A comma separated list of Tweet fields to display. Returns: GetDmConversationsIdDmEventsResponse: Response data """ @@ -83,16 +68,6 @@ def get_dm_conversations_id_dm_events( params["pagination_token"] = pagination_token if event_types is not None: params["event_types"] = ",".join(str(item) for item in event_types) - if dm_event_fields is not None: - params["dm_event.fields"] = ",".join(str(item) for item in dm_event_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) url = url.replace("{id}", str(id)) headers = {} # Make the request @@ -116,146 +91,73 @@ def get_dm_conversations_id_dm_events( return GetDmConversationsIdDmEventsResponse.model_validate(response_data) - def get_dm_events_by_participant_id( + def create_dm_by_conversation_id( self, - participant_id: str, - max_results: int = None, - pagination_token: str = None, - event_types: List = None, - dm_event_fields: List = None, - expansions: List = None, - media_fields: List = None, - user_fields: List = None, - tweet_fields: List = None, - ) -> GetDmEventsByParticipantIdResponse: + dm_conversation_id: str, + body: Optional[CreateDmByConversationIdRequest] = None, + ) -> Dict[str, Any]: """ - Get DM events for a DM conversation - Retrieves direct message events for a specific conversation. - Args: - participant_id: The ID of the participant user for the One to One DM conversation. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - event_types: The set of event_types to include in the results. - Args: - dm_event_fields: A comma separated list of DmEvent fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - user_fields: A comma separated list of User fields to display. + Create DM message by conversation ID + Sends a new direct message to a specific conversation by its ID. Args: - tweet_fields: A comma separated list of Tweet fields to display. + dm_conversation_id: The DM Conversation ID. + body: Request body Returns: - GetDmEventsByParticipantIdResponse: Response data + CreateDmByConversationIdResponse: Response data """ - url = ( - self.client.base_url + "/2/dm_conversations/with/{participant_id}/dm_events" - ) + url = self.client.base_url + "/2/dm_conversations/{dm_conversation_id}/messages" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if event_types is not None: - params["event_types"] = ",".join(str(item) for item in event_types) - if dm_event_fields is not None: - params["dm_event.fields"] = ",".join(str(item) for item in dm_event_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{participant_id}", str(participant_id)) + url = url.replace("{dm_conversation_id}", str(dm_conversation_id)) headers = {} + headers["Content-Type"] = "application/json" # Make the request if self.client.oauth2_session: - response = self.client.oauth2_session.get( + response = self.client.oauth2_session.post( url, params=params, headers=headers, + json=body.model_dump(exclude_none=True) if body else None, ) else: - response = self.client.session.get( + response = self.client.session.post( url, params=params, headers=headers, + json=body.model_dump(exclude_none=True) if body else None, ) # Check for errors response.raise_for_status() # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetDmEventsByParticipantIdResponse.model_validate(response_data) + return CreateDmByConversationIdResponse.model_validate(response_data) - def get_dm_events( + def get_events_by_id( self, - max_results: int = None, - pagination_token: str = None, - event_types: List = None, - dm_event_fields: List = None, - expansions: List = None, - media_fields: List = None, - user_fields: List = None, - tweet_fields: List = None, - ) -> GetDmEventsResponse: + event_id: Any, + ) -> GetEventsByIdResponse: """ - Get DM events - Retrieves a list of recent direct message events across all conversations. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - event_types: The set of event_types to include in the results. - Args: - dm_event_fields: A comma separated list of DmEvent fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - user_fields: A comma separated list of User fields to display. + Get DM event by ID + Retrieves details of a specific direct message event by its ID. Args: - tweet_fields: A comma separated list of Tweet fields to display. + event_id: dm event id. Returns: - GetDmEventsResponse: Response data + GetEventsByIdResponse: Response data """ - url = self.client.base_url + "/2/dm_events" + url = self.client.base_url + "/2/dm_events/{event_id}" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if event_types is not None: - params["event_types"] = ",".join(str(item) for item in event_types) - if dm_event_fields is not None: - params["dm_event.fields"] = ",".join(str(item) for item in dm_event_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) + url = url.replace("{event_id}", str(event_id)) headers = {} # Make the request if self.client.oauth2_session: @@ -275,35 +177,20 @@ def get_dm_events( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetDmEventsResponse.model_validate(response_data) + return GetEventsByIdResponse.model_validate(response_data) - def get_dm_events_by_id( + def delete_dm_events( self, - event_id: str, - dm_event_fields: List = None, - expansions: List = None, - media_fields: List = None, - user_fields: List = None, - tweet_fields: List = None, - ) -> GetDmEventsByIdResponse: + event_id: Any, + ) -> DeleteDmEventsResponse: """ - Get DM event by ID - Retrieves details of a specific direct message event by its ID. - Args: - event_id: dm event id. - Args: - dm_event_fields: A comma separated list of DmEvent fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - user_fields: A comma separated list of User fields to display. + Delete DM event + Deletes a specific direct message event by its ID, if owned by the authenticated user. Args: - tweet_fields: A comma separated list of Tweet fields to display. + event_id: The ID of the direct-message event to delete. Returns: - GetDmEventsByIdResponse: Response data + DeleteDmEventsResponse: Response data """ url = self.client.base_url + "/2/dm_events/{event_id}" # Ensure we have a valid access token @@ -312,27 +199,17 @@ def get_dm_events_by_id( if self.client.is_token_expired(): self.client.refresh_token() params = {} - if dm_event_fields is not None: - params["dm_event.fields"] = ",".join(str(item) for item in dm_event_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) url = url.replace("{event_id}", str(event_id)) headers = {} # Make the request if self.client.oauth2_session: - response = self.client.oauth2_session.get( + response = self.client.oauth2_session.delete( url, params=params, headers=headers, ) else: - response = self.client.session.get( + response = self.client.session.delete( url, params=params, headers=headers, @@ -342,67 +219,75 @@ def get_dm_events_by_id( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetDmEventsByIdResponse.model_validate(response_data) + return DeleteDmEventsResponse.model_validate(response_data) - def delete_dm_events( + def create_dm_conversations( self, - event_id: str, - ) -> DeleteDmEventsResponse: + body: Optional[CreateDmConversationsRequest] = None, + ) -> Dict[str, Any]: """ - Delete DM event - Deletes a specific direct message event by its ID, if owned by the authenticated user. - Args: - event_id: The ID of the direct-message event to delete. + Create DM conversation + Initiates a new direct message conversation with specified participants. + body: Request body Returns: - DeleteDmEventsResponse: Response data + CreateDmConversationsResponse: Response data """ - url = self.client.base_url + "/2/dm_events/{event_id}" + url = self.client.base_url + "/2/dm_conversations" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} - url = url.replace("{event_id}", str(event_id)) headers = {} + headers["Content-Type"] = "application/json" # Make the request if self.client.oauth2_session: - response = self.client.oauth2_session.delete( + response = self.client.oauth2_session.post( url, params=params, headers=headers, + json=body.model_dump(exclude_none=True) if body else None, ) else: - response = self.client.session.delete( + response = self.client.session.post( url, params=params, headers=headers, + json=body.model_dump(exclude_none=True) if body else None, ) # Check for errors response.raise_for_status() # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return DeleteDmEventsResponse.model_validate(response_data) + return CreateDmConversationsResponse.model_validate(response_data) - def create_dm_by_participant_id( + def get_dm_events_by_participant_id( self, - participant_id: str, - body: Optional[CreateDmByParticipantIdRequest] = None, - ) -> Dict[str, Any]: + participant_id: Any, + max_results: int = None, + pagination_token: Any = None, + event_types: List = None, + ) -> GetDmEventsByParticipantIdResponse: """ - Create DM message by participant ID - Sends a new direct message to a specific participant by their ID. + Get DM events for a DM conversation + Retrieves direct message events for a specific conversation. Args: - participant_id: The ID of the recipient user that will receive the DM. - body: Request body + participant_id: The ID of the participant user for the One to One DM conversation. + Args: + max_results: The maximum number of results. + Args: + pagination_token: This parameter is used to get a specified 'page' of results. + Args: + event_types: The set of event_types to include in the results. Returns: - CreateDmByParticipantIdResponse: Response data + GetDmEventsByParticipantIdResponse: Response data """ url = ( - self.client.base_url + "/2/dm_conversations/with/{participant_id}/messages" + self.client.base_url + "/2/dm_conversations/with/{participant_id}/dm_events" ) # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: @@ -410,97 +295,112 @@ def create_dm_by_participant_id( if self.client.is_token_expired(): self.client.refresh_token() params = {} + if max_results is not None: + params["max_results"] = max_results + if pagination_token is not None: + params["pagination_token"] = pagination_token + if event_types is not None: + params["event_types"] = ",".join(str(item) for item in event_types) url = url.replace("{participant_id}", str(participant_id)) headers = {} - headers["Content-Type"] = "application/json" # Make the request if self.client.oauth2_session: - response = self.client.oauth2_session.post( + response = self.client.oauth2_session.get( url, params=params, headers=headers, - json=body.model_dump(exclude_none=True) if body else None, ) else: - response = self.client.session.post( + response = self.client.session.get( url, params=params, headers=headers, - json=body.model_dump(exclude_none=True) if body else None, ) # Check for errors response.raise_for_status() # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return CreateDmByParticipantIdResponse.model_validate(response_data) + return GetDmEventsByParticipantIdResponse.model_validate(response_data) - def create_dm_by_conversation_id( + def get_events( self, - dm_conversation_id: str, - body: Optional[CreateDmByConversationIdRequest] = None, - ) -> Dict[str, Any]: + max_results: int = None, + pagination_token: Any = None, + event_types: List = None, + ) -> GetEventsResponse: """ - Create DM message by conversation ID - Sends a new direct message to a specific conversation by its ID. + Get DM events + Retrieves a list of recent direct message events across all conversations. Args: - dm_conversation_id: The DM Conversation ID. - body: Request body + max_results: The maximum number of results. + Args: + pagination_token: This parameter is used to get a specified 'page' of results. + Args: + event_types: The set of event_types to include in the results. Returns: - CreateDmByConversationIdResponse: Response data + GetEventsResponse: Response data """ - url = self.client.base_url + "/2/dm_conversations/{dm_conversation_id}/messages" + url = self.client.base_url + "/2/dm_events" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} - url = url.replace("{dm_conversation_id}", str(dm_conversation_id)) + if max_results is not None: + params["max_results"] = max_results + if pagination_token is not None: + params["pagination_token"] = pagination_token + if event_types is not None: + params["event_types"] = ",".join(str(item) for item in event_types) headers = {} - headers["Content-Type"] = "application/json" # Make the request if self.client.oauth2_session: - response = self.client.oauth2_session.post( + response = self.client.oauth2_session.get( url, params=params, headers=headers, - json=body.model_dump(exclude_none=True) if body else None, ) else: - response = self.client.session.post( + response = self.client.session.get( url, params=params, headers=headers, - json=body.model_dump(exclude_none=True) if body else None, ) # Check for errors response.raise_for_status() # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return CreateDmByConversationIdResponse.model_validate(response_data) + return GetEventsResponse.model_validate(response_data) - def create_dm_conversations( + def create_dm_by_participant_id( self, - body: Optional[CreateDmConversationsRequest] = None, + participant_id: Any, + body: Optional[CreateDmByParticipantIdRequest] = None, ) -> Dict[str, Any]: """ - Create DM conversation - Initiates a new direct message conversation with specified participants. + Create DM message by participant ID + Sends a new direct message to a specific participant by their ID. + Args: + participant_id: The ID of the recipient user that will receive the DM. body: Request body Returns: - CreateDmConversationsResponse: Response data + CreateDmByParticipantIdResponse: Response data """ - url = self.client.base_url + "/2/dm_conversations" + url = ( + self.client.base_url + "/2/dm_conversations/with/{participant_id}/messages" + ) # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} + url = url.replace("{participant_id}", str(participant_id)) headers = {} headers["Content-Type"] = "application/json" # Make the request @@ -523,4 +423,4 @@ def create_dm_conversations( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return CreateDmConversationsResponse.model_validate(response_data) + return CreateDmByParticipantIdResponse.model_validate(response_data) diff --git a/xdk/python/xdk/direct_messages/models.py b/xdk/python/xdk/direct_messages/models.py index 55b15fb5..7b161eb7 100644 --- a/xdk/python/xdk/direct_messages/models.py +++ b/xdk/python/xdk/direct_messages/models.py @@ -1,7 +1,7 @@ """ -Direct_Messages models for the X API. +direct messages models for the X API. -This module provides models for the Direct_Messages endpoints of the X API. +This module provides models for the direct messages endpoints of the X API. """ from typing import Dict, List, Optional, Any, Union, Literal @@ -9,11 +9,11 @@ from datetime import datetime -# Models for getDmConversationsIdDmEvents +# Models for get_dm_conversations_id_dm_events class GetDmConversationsIdDmEventsResponse(BaseModel): - """Response model for getDmConversationsIdDmEvents""" + """Response model for get_dm_conversations_id_dm_events""" data: Optional[List] = None errors: Optional[List] = None @@ -46,97 +46,59 @@ class GetDmConversationsIdDmEventsResponseMeta(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for getDmEventsByParticipantId +# Models for create_dm_by_conversation_id -class GetDmEventsByParticipantIdResponse(BaseModel): - """Response model for getDmEventsByParticipantId""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetDmEventsByParticipantIdResponseIncludes"] = None - meta: Optional["GetDmEventsByParticipantIdResponseMeta"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetDmEventsByParticipantIdResponseIncludes(BaseModel): - """Nested model for GetDmEventsByParticipantIdResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetDmEventsByParticipantIdResponseMeta(BaseModel): - """Nested model for GetDmEventsByParticipantIdResponseMeta""" +class CreateDmByConversationIdRequest(BaseModel): + """Request model for create_dm_by_conversation_id""" - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None + attachments: Optional[List] = Field( + default=None, description="Attachments to a DM Event." + ) + text: Optional[str] = Field(default=None, description="Text of the message.") + attachments: Optional[List] = Field( + default=None, description="Attachments to a DM Event." + ) + text: Optional[str] = Field(default=None, description="Text of the message.") model_config = ConfigDict(populate_by_name=True) -# Models for getDmEvents - - -class GetDmEventsResponse(BaseModel): - """Response model for getDmEvents""" +class CreateDmByConversationIdResponse(BaseModel): + """Response model for create_dm_by_conversation_id""" - data: Optional[List] = None + data: Optional["CreateDmByConversationIdResponseData"] = Field(default_factory=dict) errors: Optional[List] = None - includes: Optional["GetDmEventsResponseIncludes"] = None - meta: Optional["GetDmEventsResponseMeta"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetDmEventsResponseIncludes(BaseModel): - """Nested model for GetDmEventsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class GetDmEventsResponseMeta(BaseModel): - """Nested model for GetDmEventsResponseMeta""" +class CreateDmByConversationIdResponseData(BaseModel): + """Nested model for CreateDmByConversationIdResponseData""" - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None + dm_conversation_id: Optional[str] = None + dm_event_id: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -# Models for getDmEventsById +# Models for get_events_by_id -class GetDmEventsByIdResponse(BaseModel): - """Response model for getDmEventsById""" +class GetEventsByIdResponse(BaseModel): + """Response model for get_events_by_id""" - data: Optional["GetDmEventsByIdResponseData"] = Field(default_factory=dict) + data: Optional["GetEventsByIdResponseData"] = Field(default_factory=dict) errors: Optional[List] = None - includes: Optional["GetDmEventsByIdResponseIncludes"] = None + includes: Optional["GetEventsByIdResponseIncludes"] = None model_config = ConfigDict(populate_by_name=True) -class GetDmEventsByIdResponseData(BaseModel): - """Nested model for GetDmEventsByIdResponseData""" +class GetEventsByIdResponseData(BaseModel): + """Nested model for GetEventsByIdResponseData""" - attachments: Optional["GetDmEventsByIdResponseDataAttachments"] = None + attachments: Optional["GetEventsByIdResponseDataAttachments"] = None cashtags: Optional[List] = None created_at: Optional[str] = None dm_conversation_id: Optional[str] = None @@ -153,8 +115,8 @@ class GetDmEventsByIdResponseData(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetDmEventsByIdResponseDataAttachments(BaseModel): - """Nested model for GetDmEventsByIdResponseDataAttachments""" +class GetEventsByIdResponseDataAttachments(BaseModel): + """Nested model for GetEventsByIdResponseDataAttachments""" card_ids: Optional[List] = None media_keys: Optional[List] = None @@ -162,8 +124,8 @@ class GetDmEventsByIdResponseDataAttachments(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetDmEventsByIdResponseIncludes(BaseModel): - """Nested model for GetDmEventsByIdResponseIncludes""" +class GetEventsByIdResponseIncludes(BaseModel): + """Nested model for GetEventsByIdResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -175,11 +137,11 @@ class GetDmEventsByIdResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for deleteDmEvents +# Models for delete_dm_events class DeleteDmEventsResponse(BaseModel): - """Response model for deleteDmEvents""" + """Response model for delete_dm_events""" data: Optional["DeleteDmEventsResponseData"] = None errors: Optional[List] = None @@ -195,35 +157,30 @@ class DeleteDmEventsResponseData(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for createDmByParticipantId +# Models for create_dm_conversations -class CreateDmByParticipantIdRequest(BaseModel): - """Request model for createDmByParticipantId""" +class CreateDmConversationsRequest(BaseModel): + """Request model for create_dm_conversations""" - attachments: Optional[List] = Field( - default=None, description="Attachments to a DM Event." - ) - text: Optional[str] = Field(default=None, description="Text of the message.") - attachments: Optional[List] = Field( - default=None, description="Attachments to a DM Event." - ) - text: Optional[str] = Field(default=None, description="Text of the message.") + conversation_type: Optional[str] = None + message: Any = None + participant_ids: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class CreateDmByParticipantIdResponse(BaseModel): - """Response model for createDmByParticipantId""" +class CreateDmConversationsResponse(BaseModel): + """Response model for create_dm_conversations""" - data: Optional["CreateDmByParticipantIdResponseData"] = Field(default_factory=dict) + data: Optional["CreateDmConversationsResponseData"] = Field(default_factory=dict) errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class CreateDmByParticipantIdResponseData(BaseModel): - """Nested model for CreateDmByParticipantIdResponseData""" +class CreateDmConversationsResponseData(BaseModel): + """Nested model for CreateDmConversationsResponseData""" dm_conversation_id: Optional[str] = None dm_event_id: Optional[str] = None @@ -231,66 +188,109 @@ class CreateDmByParticipantIdResponseData(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for createDmByConversationId +# Models for get_dm_events_by_participant_id -class CreateDmByConversationIdRequest(BaseModel): - """Request model for createDmByConversationId""" +class GetDmEventsByParticipantIdResponse(BaseModel): + """Response model for get_dm_events_by_participant_id""" - attachments: Optional[List] = Field( - default=None, description="Attachments to a DM Event." - ) - text: Optional[str] = Field(default=None, description="Text of the message.") - attachments: Optional[List] = Field( - default=None, description="Attachments to a DM Event." - ) - text: Optional[str] = Field(default=None, description="Text of the message.") + data: Optional[List] = None + errors: Optional[List] = None + includes: Optional["GetDmEventsByParticipantIdResponseIncludes"] = None + meta: Optional["GetDmEventsByParticipantIdResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class CreateDmByConversationIdResponse(BaseModel): - """Response model for createDmByConversationId""" +class GetDmEventsByParticipantIdResponseIncludes(BaseModel): + """Nested model for GetDmEventsByParticipantIdResponseIncludes""" - data: Optional["CreateDmByConversationIdResponseData"] = Field(default_factory=dict) + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetDmEventsByParticipantIdResponseMeta(BaseModel): + """Nested model for GetDmEventsByParticipantIdResponseMeta""" + + next_token: Optional[str] = None + previous_token: Optional[str] = None + result_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for get_events + + +class GetEventsResponse(BaseModel): + """Response model for get_events""" + + data: Optional[List] = None errors: Optional[List] = None + includes: Optional["GetEventsResponseIncludes"] = None + meta: Optional["GetEventsResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class CreateDmByConversationIdResponseData(BaseModel): - """Nested model for CreateDmByConversationIdResponseData""" +class GetEventsResponseIncludes(BaseModel): + """Nested model for GetEventsResponseIncludes""" - dm_conversation_id: Optional[str] = None - dm_event_id: Optional[str] = None + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -# Models for createDmConversations +class GetEventsResponseMeta(BaseModel): + """Nested model for GetEventsResponseMeta""" + next_token: Optional[str] = None + previous_token: Optional[str] = None + result_count: Optional[int] = None -class CreateDmConversationsRequest(BaseModel): - """Request model for createDmConversations""" + model_config = ConfigDict(populate_by_name=True) - conversation_type: Optional[str] = None - message: Any = None - participant_ids: Optional[List] = None + +# Models for create_dm_by_participant_id + + +class CreateDmByParticipantIdRequest(BaseModel): + """Request model for create_dm_by_participant_id""" + + attachments: Optional[List] = Field( + default=None, description="Attachments to a DM Event." + ) + text: Optional[str] = Field(default=None, description="Text of the message.") + attachments: Optional[List] = Field( + default=None, description="Attachments to a DM Event." + ) + text: Optional[str] = Field(default=None, description="Text of the message.") model_config = ConfigDict(populate_by_name=True) -class CreateDmConversationsResponse(BaseModel): - """Response model for createDmConversations""" +class CreateDmByParticipantIdResponse(BaseModel): + """Response model for create_dm_by_participant_id""" - data: Optional["CreateDmConversationsResponseData"] = Field(default_factory=dict) + data: Optional["CreateDmByParticipantIdResponseData"] = Field(default_factory=dict) errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class CreateDmConversationsResponseData(BaseModel): - """Nested model for CreateDmConversationsResponseData""" +class CreateDmByParticipantIdResponseData(BaseModel): + """Nested model for CreateDmByParticipantIdResponseData""" dm_conversation_id: Optional[str] = None dm_event_id: Optional[str] = None diff --git a/xdk/python/xdk/general/__init__.py b/xdk/python/xdk/general/__init__.py index 5de7148e..7e7a602f 100644 --- a/xdk/python/xdk/general/__init__.py +++ b/xdk/python/xdk/general/__init__.py @@ -1,7 +1,7 @@ """ -General module for the X API. +general module for the X API. -This module provides access to the General endpoints of the X API. +This module provides access to the general endpoints of the X API. """ from .client import GeneralClient diff --git a/xdk/python/xdk/general/client.py b/xdk/python/xdk/general/client.py index 87ac403b..59380ff5 100644 --- a/xdk/python/xdk/general/client.py +++ b/xdk/python/xdk/general/client.py @@ -1,7 +1,7 @@ """ -General client for the X API. +general client for the X API. -This module provides a client for interacting with the General endpoints of the X API. +This module provides a client for interacting with the general endpoints of the X API. """ from __future__ import annotations @@ -17,7 +17,7 @@ class GeneralClient: - """Client for General operations""" + """Client for general operations""" def __init__(self, client: Client): diff --git a/xdk/python/xdk/general/models.py b/xdk/python/xdk/general/models.py index 8d41659e..a4075288 100644 --- a/xdk/python/xdk/general/models.py +++ b/xdk/python/xdk/general/models.py @@ -1,7 +1,7 @@ """ -General models for the X API. +general models for the X API. -This module provides models for the General endpoints of the X API. +This module provides models for the general endpoints of the X API. """ from typing import Dict, List, Optional, Any, Union, Literal @@ -9,10 +9,10 @@ from datetime import datetime -# Models for getOpenApiSpec +# Models for get_open_api_spec class GetOpenApiSpecResponse(BaseModel): - """Response model for getOpenApiSpec""" + """Response model for get_open_api_spec""" model_config = ConfigDict(populate_by_name=True) diff --git a/xdk/python/xdk/likes/__init__.py b/xdk/python/xdk/likes/__init__.py deleted file mode 100644 index 1a9af0b7..00000000 --- a/xdk/python/xdk/likes/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Likes module for the X API. - -This module provides access to the Likes endpoints of the X API. -""" - -from .client import LikesClient - -__all__ = ["LikesClient"] diff --git a/xdk/python/xdk/likes/client.py b/xdk/python/xdk/likes/client.py deleted file mode 100644 index 7e9b5833..00000000 --- a/xdk/python/xdk/likes/client.py +++ /dev/null @@ -1,177 +0,0 @@ -""" -Likes client for the X API. - -This module provides a client for interacting with the Likes endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - StreamLikesFirehoseResponse, - StreamLikesSample10Response, -) - - -class LikesClient: - """Client for Likes operations""" - - - def __init__(self, client: Client): - self.client = client - - - def stream_likes_firehose( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - like_with_tweet_author_fields: List = None, - expansions: List = None, - user_fields: List = None, - tweet_fields: List = None, - ) -> StreamLikesFirehoseResponse: - """ - Stream all Likes - Streams all public Likes in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Likes will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - like_with_tweet_author_fields: A comma separated list of LikeWithTweetAuthor fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - StreamLikesFirehoseResponse: Response data - """ - url = self.client.base_url + "/2/likes/firehose/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if like_with_tweet_author_fields is not None: - params["like_with_tweet_author.fields"] = ",".join( - str(item) for item in like_with_tweet_author_fields - ) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamLikesFirehoseResponse.model_validate(response_data) - - - def stream_likes_sample10( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - like_with_tweet_author_fields: List = None, - expansions: List = None, - user_fields: List = None, - tweet_fields: List = None, - ) -> StreamLikesSample10Response: - """ - Stream sampled Likes - Streams a 10% sample of public Likes in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Likes will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - like_with_tweet_author_fields: A comma separated list of LikeWithTweetAuthor fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - StreamLikesSample10Response: Response data - """ - url = self.client.base_url + "/2/likes/sample10/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if like_with_tweet_author_fields is not None: - params["like_with_tweet_author.fields"] = ",".join( - str(item) for item in like_with_tweet_author_fields - ) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamLikesSample10Response.model_validate(response_data) diff --git a/xdk/python/xdk/likes/models.py b/xdk/python/xdk/likes/models.py deleted file mode 100644 index 911abe4b..00000000 --- a/xdk/python/xdk/likes/models.py +++ /dev/null @@ -1,85 +0,0 @@ -""" -Likes models for the X API. - -This module provides models for the Likes endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field, ConfigDict -from datetime import datetime - - -# Models for streamLikesFirehose - - -class StreamLikesFirehoseResponse(BaseModel): - """Response model for streamLikesFirehose""" - - data: Optional["StreamLikesFirehoseResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreamLikesFirehoseResponseIncludes"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamLikesFirehoseResponseData(BaseModel): - """Nested model for StreamLikesFirehoseResponseData""" - - created_at: Optional[str] = None - id: Optional[str] = None - liked_tweet_id: Optional[str] = None - timestamp_ms: Optional[int] = None - tweet_author_id: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamLikesFirehoseResponseIncludes(BaseModel): - """Nested model for StreamLikesFirehoseResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for streamLikesSample10 - - -class StreamLikesSample10Response(BaseModel): - """Response model for streamLikesSample10""" - - data: Optional["StreamLikesSample10ResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreamLikesSample10ResponseIncludes"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamLikesSample10ResponseData(BaseModel): - """Nested model for StreamLikesSample10ResponseData""" - - created_at: Optional[str] = None - id: Optional[str] = None - liked_tweet_id: Optional[str] = None - timestamp_ms: Optional[int] = None - tweet_author_id: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamLikesSample10ResponseIncludes(BaseModel): - """Nested model for StreamLikesSample10ResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) diff --git a/xdk/python/xdk/lists/__init__.py b/xdk/python/xdk/lists/__init__.py index 8a25c7fb..0cf27fff 100644 --- a/xdk/python/xdk/lists/__init__.py +++ b/xdk/python/xdk/lists/__init__.py @@ -1,7 +1,7 @@ """ -Lists module for the X API. +lists module for the X API. -This module provides access to the Lists endpoints of the X API. +This module provides access to the lists endpoints of the X API. """ from .client import ListsClient diff --git a/xdk/python/xdk/lists/client.py b/xdk/python/xdk/lists/client.py index a1a9a0a3..69cedb4b 100644 --- a/xdk/python/xdk/lists/client.py +++ b/xdk/python/xdk/lists/client.py @@ -1,7 +1,7 @@ """ -Lists client for the X API. +lists client for the X API. -This module provides a client for interacting with the Lists endpoints of the X API. +This module provides a client for interacting with the lists endpoints of the X API. """ from __future__ import annotations @@ -12,175 +12,39 @@ if TYPE_CHECKING: from ..client import Client from .models import ( - GetUsersListMembershipsResponse, - GetUsersFollowedListsResponse, FollowListRequest, FollowListResponse, - GetListsByIdResponse, - UpdateListsRequest, - UpdateListsResponse, - DeleteListsResponse, - GetUsersPinnedListsResponse, + GetByIdResponse, + UpdateRequest, + UpdateResponse, + DeleteResponse, + GetMembersResponse, + AddMemberRequest, + AddMemberResponse, + GetFollowersResponse, + GetPostsResponse, + UnfollowListResponse, + GetUsersPinnedResponse, PinListRequest, PinListResponse, + CreateRequest, + CreateResponse, + RemoveMemberByUserIdResponse, UnpinListResponse, - RemoveListsMemberByUserIdResponse, - GetUsersOwnedListsResponse, - CreateListsRequest, - CreateListsResponse, - AddListsMemberRequest, - AddListsMemberResponse, - UnfollowListResponse, ) class ListsClient: - """Client for Lists operations""" + """Client for lists operations""" def __init__(self, client: Client): self.client = client - def get_users_list_memberships( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - list_fields: List = None, - expansions: List = None, - user_fields: List = None, - ) -> GetUsersListMembershipsResponse: - """ - Get List memberships - Retrieves a list of Lists that a specific User is a member of by their ID. - Args: - id: The ID of the User to lookup. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - list_fields: A comma separated list of List fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Returns: - GetUsersListMembershipsResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/list_memberships" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if list_fields is not None: - params["list.fields"] = ",".join(str(item) for item in list_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetUsersListMembershipsResponse.model_validate(response_data) - - - def get_users_followed_lists( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - list_fields: List = None, - expansions: List = None, - user_fields: List = None, - ) -> GetUsersFollowedListsResponse: - """ - Get followed Lists - Retrieves a list of Lists followed by a specific User by their ID. - Args: - id: The ID of the User to lookup. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - list_fields: A comma separated list of List fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Returns: - GetUsersFollowedListsResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/followed_lists" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if list_fields is not None: - params["list.fields"] = ",".join(str(item) for item in list_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetUsersFollowedListsResponse.model_validate(response_data) - - def follow_list( self, - id: str, + id: Any, body: Optional[FollowListRequest] = None, ) -> FollowListResponse: """ @@ -225,26 +89,17 @@ def follow_list( return FollowListResponse.model_validate(response_data) - def get_lists_by_id( + def get_by_id( self, - id: str, - list_fields: List = None, - expansions: List = None, - user_fields: List = None, - ) -> GetListsByIdResponse: + id: Any, + ) -> GetByIdResponse: """ Get List by ID Retrieves details of a specific List by its ID. Args: id: The ID of the List. - Args: - list_fields: A comma separated list of List fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. Returns: - GetListsByIdResponse: Response data + GetByIdResponse: Response data """ url = self.client.base_url + "/2/lists/{id}" if self.client.bearer_token: @@ -261,12 +116,6 @@ def get_lists_by_id( if self.client.is_token_expired(): self.client.refresh_token() params = {} - if list_fields is not None: - params["list.fields"] = ",".join(str(item) for item in list_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) url = url.replace("{id}", str(id)) headers = {} # Make the request @@ -280,14 +129,14 @@ def get_lists_by_id( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetListsByIdResponse.model_validate(response_data) + return GetByIdResponse.model_validate(response_data) - def update_lists( + def update( self, - id: str, - body: Optional[UpdateListsRequest] = None, - ) -> UpdateListsResponse: + id: Any, + body: Optional[UpdateRequest] = None, + ) -> UpdateResponse: """ Update List Updates the details of a specific List owned by the authenticated user by its ID. @@ -295,7 +144,7 @@ def update_lists( id: The ID of the List to modify. body: Request body Returns: - UpdateListsResponse: Response data + UpdateResponse: Response data """ url = self.client.base_url + "/2/lists/{id}" # Ensure we have a valid access token @@ -327,20 +176,20 @@ def update_lists( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return UpdateListsResponse.model_validate(response_data) + return UpdateResponse.model_validate(response_data) - def delete_lists( + def delete( self, - id: str, - ) -> DeleteListsResponse: + id: Any, + ) -> DeleteResponse: """ Delete List Deletes a specific List owned by the authenticated user by its ID. Args: id: The ID of the List to delete. Returns: - DeleteListsResponse: Response data + DeleteResponse: Response data """ url = self.client.base_url + "/2/lists/{id}" # Ensure we have a valid access token @@ -369,81 +218,77 @@ def delete_lists( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return DeleteListsResponse.model_validate(response_data) + return DeleteResponse.model_validate(response_data) - def get_users_pinned_lists( + def get_members( self, - id: str, - list_fields: List = None, - expansions: List = None, - user_fields: List = None, - ) -> GetUsersPinnedListsResponse: + id: Any, + max_results: int = None, + pagination_token: Any = None, + ) -> GetMembersResponse: """ - Get pinned Lists - Retrieves a list of Lists pinned by the authenticated user. + Get List members + Retrieves a list of Users who are members of a specific List by its ID. Args: - id: The ID of the authenticated source User for whom to return results. - Args: - list_fields: A comma separated list of List fields to display. + id: The ID of the List. Args: - expansions: A comma separated list of fields to expand. + max_results: The maximum number of results. Args: - user_fields: A comma separated list of User fields to display. + pagination_token: This parameter is used to get a specified 'page' of results. Returns: - GetUsersPinnedListsResponse: Response data + GetMembersResponse: Response data """ - url = self.client.base_url + "/2/users/{id}/pinned_lists" + url = self.client.base_url + "/2/lists/{id}/members" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} - if list_fields is not None: - params["list.fields"] = ",".join(str(item) for item in list_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) + if max_results is not None: + params["max_results"] = max_results + if pagination_token is not None: + params["pagination_token"] = pagination_token url = url.replace("{id}", str(id)) headers = {} # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) + response = self.client.session.get( + url, + params=params, + headers=headers, + ) # Check for errors response.raise_for_status() # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetUsersPinnedListsResponse.model_validate(response_data) + return GetMembersResponse.model_validate(response_data) - def pin_list( + def add_member( self, - id: str, - body: PinListRequest, - ) -> PinListResponse: + id: Any, + body: Optional[AddMemberRequest] = None, + ) -> AddMemberResponse: """ - Pin List - Causes the authenticated user to pin a specific List by its ID. + Add List member + Adds a User to a specific List by its ID. Args: - id: The ID of the authenticated source User that will pin the List. + id: The ID of the List for which to add a member. body: Request body Returns: - PinListResponse: Response data + AddMemberResponse: Response data """ - url = self.client.base_url + "/2/users/{id}/pinned_lists" + url = self.client.base_url + "/2/lists/{id}/members" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh @@ -473,25 +318,131 @@ def pin_list( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return PinListResponse.model_validate(response_data) + return AddMemberResponse.model_validate(response_data) - def unpin_list( + def get_followers( self, - id: str, - list_id: str, - ) -> UnpinListResponse: + id: Any, + max_results: int = None, + pagination_token: Any = None, + ) -> GetFollowersResponse: """ - Unpin List - Causes the authenticated user to unpin a specific List by its ID. + Get List followers + Retrieves a list of Users who follow a specific List by its ID. Args: - id: The ID of the authenticated source User for whom to return results. + id: The ID of the List. Args: - list_id: The ID of the List to unpin. + max_results: The maximum number of results. + Args: + pagination_token: This parameter is used to get a specified 'page' of results. Returns: - UnpinListResponse: Response data + GetFollowersResponse: Response data """ - url = self.client.base_url + "/2/users/{id}/pinned_lists/{list_id}" + url = self.client.base_url + "/2/lists/{id}/followers" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + if max_results is not None: + params["max_results"] = max_results + if pagination_token is not None: + params["pagination_token"] = pagination_token + url = url.replace("{id}", str(id)) + headers = {} + # Make the request + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetFollowersResponse.model_validate(response_data) + + + def get_posts( + self, + id: Any, + max_results: int = None, + pagination_token: Any = None, + ) -> GetPostsResponse: + """ + Get List Posts + Retrieves a list of Posts associated with a specific List by its ID. + Args: + id: The ID of the List. + Args: + max_results: The maximum number of results. + Args: + pagination_token: This parameter is used to get the next 'page' of results. + Returns: + GetPostsResponse: Response data + """ + url = self.client.base_url + "/2/lists/{id}/tweets" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + if max_results is not None: + params["max_results"] = max_results + if pagination_token is not None: + params["pagination_token"] = pagination_token + url = url.replace("{id}", str(id)) + headers = {} + # Make the request + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetPostsResponse.model_validate(response_data) + + + def unfollow_list( + self, + id: Any, + list_id: Any, + ) -> UnfollowListResponse: + """ + Unfollow List + Causes the authenticated user to unfollow a specific List by its ID. + Args: + id: The ID of the authenticated source User that will unfollow the List. + Args: + list_id: The ID of the List to unfollow. + Returns: + UnfollowListResponse: Response data + """ + url = self.client.base_url + "/2/users/{id}/followed_lists/{list_id}" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh @@ -519,25 +470,22 @@ def unpin_list( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return UnpinListResponse.model_validate(response_data) + return UnfollowListResponse.model_validate(response_data) - def remove_lists_member_by_user_id( + def get_users_pinned( self, - id: str, - user_id: str, - ) -> RemoveListsMemberByUserIdResponse: + id: Any, + ) -> GetUsersPinnedResponse: """ - Remove List member - Removes a User from a specific List by its ID and the User’s ID. - Args: - id: The ID of the List to remove a member. + Get pinned Lists + Retrieves a list of Lists pinned by the authenticated user. Args: - user_id: The ID of User that will be removed from the List. + id: The ID of the authenticated source User for whom to return results. Returns: - RemoveListsMemberByUserIdResponse: Response data + GetUsersPinnedResponse: Response data """ - url = self.client.base_url + "/2/lists/{id}/members/{user_id}" + url = self.client.base_url + "/2/users/{id}/pinned_lists" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh @@ -545,17 +493,16 @@ def remove_lists_member_by_user_id( self.client.refresh_token() params = {} url = url.replace("{id}", str(id)) - url = url.replace("{user_id}", str(user_id)) headers = {} # Make the request if self.client.oauth2_session: - response = self.client.oauth2_session.delete( + response = self.client.oauth2_session.get( url, params=params, headers=headers, ) else: - response = self.client.session.delete( + response = self.client.session.get( url, params=params, headers=headers, @@ -565,87 +512,66 @@ def remove_lists_member_by_user_id( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return RemoveListsMemberByUserIdResponse.model_validate(response_data) + return GetUsersPinnedResponse.model_validate(response_data) - def get_users_owned_lists( + def pin_list( self, - id: str, - max_results: int = None, - pagination_token: str = None, - list_fields: List = None, - expansions: List = None, - user_fields: List = None, - ) -> GetUsersOwnedListsResponse: + id: Any, + body: PinListRequest, + ) -> PinListResponse: """ - Get owned Lists - Retrieves a list of Lists owned by a specific User by their ID. - Args: - id: The ID of the User to lookup. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - list_fields: A comma separated list of List fields to display. - Args: - expansions: A comma separated list of fields to expand. + Pin List + Causes the authenticated user to pin a specific List by its ID. Args: - user_fields: A comma separated list of User fields to display. + id: The ID of the authenticated source User that will pin the List. + body: Request body Returns: - GetUsersOwnedListsResponse: Response data + PinListResponse: Response data """ - url = self.client.base_url + "/2/users/{id}/owned_lists" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) + url = self.client.base_url + "/2/users/{id}/pinned_lists" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if list_fields is not None: - params["list.fields"] = ",".join(str(item) for item in list_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) url = url.replace("{id}", str(id)) headers = {} + headers["Content-Type"] = "application/json" # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) + if self.client.oauth2_session: + response = self.client.oauth2_session.post( + url, + params=params, + headers=headers, + json=body.model_dump(exclude_none=True) if body else None, + ) + else: + response = self.client.session.post( + url, + params=params, + headers=headers, + json=body.model_dump(exclude_none=True) if body else None, + ) # Check for errors response.raise_for_status() # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetUsersOwnedListsResponse.model_validate(response_data) + return PinListResponse.model_validate(response_data) - def create_lists( + def create( self, - body: Optional[CreateListsRequest] = None, - ) -> CreateListsResponse: + body: Optional[CreateRequest] = None, + ) -> CreateResponse: """ Create List Creates a new List for the authenticated user. body: Request body Returns: - CreateListsResponse: Response data + CreateResponse: Response data """ url = self.client.base_url + "/2/lists" # Ensure we have a valid access token @@ -676,24 +602,25 @@ def create_lists( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return CreateListsResponse.model_validate(response_data) + return CreateResponse.model_validate(response_data) - def add_lists_member( + def remove_member_by_user_id( self, - id: str, - body: Optional[AddListsMemberRequest] = None, - ) -> AddListsMemberResponse: + id: Any, + user_id: Any, + ) -> RemoveMemberByUserIdResponse: """ - Add List member - Adds a User to a specific List by its ID. + Remove List member + Removes a User from a specific List by its ID and the User’s ID. Args: - id: The ID of the List for which to add a member. - body: Request body + id: The ID of the List to remove a member. + Args: + user_id: The ID of User that will be removed from the List. Returns: - AddListsMemberResponse: Response data + RemoveMemberByUserIdResponse: Response data """ - url = self.client.base_url + "/2/lists/{id}/members" + url = self.client.base_url + "/2/lists/{id}/members/{user_id}" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh @@ -701,47 +628,45 @@ def add_lists_member( self.client.refresh_token() params = {} url = url.replace("{id}", str(id)) + url = url.replace("{user_id}", str(user_id)) headers = {} - headers["Content-Type"] = "application/json" # Make the request if self.client.oauth2_session: - response = self.client.oauth2_session.post( + response = self.client.oauth2_session.delete( url, params=params, headers=headers, - json=body.model_dump(exclude_none=True) if body else None, ) else: - response = self.client.session.post( + response = self.client.session.delete( url, params=params, headers=headers, - json=body.model_dump(exclude_none=True) if body else None, ) # Check for errors response.raise_for_status() # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return AddListsMemberResponse.model_validate(response_data) + return RemoveMemberByUserIdResponse.model_validate(response_data) - def unfollow_list( + def unpin_list( self, - id: str, - list_id: str, - ) -> UnfollowListResponse: + id: Any, + list_id: Any, + ) -> UnpinListResponse: """ - Unfollow List - Causes the authenticated user to unfollow a specific List by its ID. + Unpin List + Causes the authenticated user to unpin a specific List by its ID. Args: - id: The ID of the authenticated source User that will unfollow the List. + id: The ID of the authenticated source User for whom to return results. Args: - list_id: The ID of the List to unfollow. + list_id: The ID of the List to unpin. Returns: - UnfollowListResponse: Response data + UnpinListResponse: Response data """ - url = self.client.base_url + "/2/users/{id}/followed_lists/{list_id}" + url = self.client.base_url + "/2/users/{id}/pinned_lists/{list_id}" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh @@ -769,4 +694,4 @@ def unfollow_list( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return UnfollowListResponse.model_validate(response_data) + return UnpinListResponse.model_validate(response_data) diff --git a/xdk/python/xdk/lists/models.py b/xdk/python/xdk/lists/models.py index 1c475c5e..7022b8cd 100644 --- a/xdk/python/xdk/lists/models.py +++ b/xdk/python/xdk/lists/models.py @@ -1,7 +1,7 @@ """ -Lists models for the X API. +lists models for the X API. -This module provides models for the Lists endpoints of the X API. +This module provides models for the lists endpoints of the X API. """ from typing import Dict, List, Optional, Any, Union, Literal @@ -9,85 +9,11 @@ from datetime import datetime -# Models for getUsersListMemberships - - -class GetUsersListMembershipsResponse(BaseModel): - """Response model for getUsersListMemberships""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetUsersListMembershipsResponseIncludes"] = None - meta: Optional["GetUsersListMembershipsResponseMeta"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetUsersListMembershipsResponseIncludes(BaseModel): - """Nested model for GetUsersListMembershipsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetUsersListMembershipsResponseMeta(BaseModel): - """Nested model for GetUsersListMembershipsResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getUsersFollowedLists - - -class GetUsersFollowedListsResponse(BaseModel): - """Response model for getUsersFollowedLists""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetUsersFollowedListsResponseIncludes"] = None - meta: Optional["GetUsersFollowedListsResponseMeta"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetUsersFollowedListsResponseIncludes(BaseModel): - """Nested model for GetUsersFollowedListsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetUsersFollowedListsResponseMeta(BaseModel): - """Nested model for GetUsersFollowedListsResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for followList +# Models for follow_list class FollowListRequest(BaseModel): - """Request model for followList""" + """Request model for follow_list""" list_id: Optional[str] = None @@ -95,7 +21,7 @@ class FollowListRequest(BaseModel): class FollowListResponse(BaseModel): - """Response model for followList""" + """Response model for follow_list""" data: Optional["FollowListResponseData"] = None errors: Optional[List] = None @@ -111,23 +37,23 @@ class FollowListResponseData(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for getListsById +# Models for get_by_id -class GetListsByIdResponse(BaseModel): - """Response model for getListsById""" +class GetByIdResponse(BaseModel): + """Response model for get_by_id""" - data: Optional["GetListsByIdResponseData"] = Field( + data: Optional["GetByIdResponseData"] = Field( description="A X List is a curated group of accounts.", default_factory=dict ) errors: Optional[List] = None - includes: Optional["GetListsByIdResponseIncludes"] = None + includes: Optional["GetByIdResponseIncludes"] = None model_config = ConfigDict(populate_by_name=True) -class GetListsByIdResponseData(BaseModel): - """Nested model for GetListsByIdResponseData""" +class GetByIdResponseData(BaseModel): + """Nested model for GetByIdResponseData""" created_at: Optional[str] = None description: Optional[str] = None @@ -141,8 +67,8 @@ class GetListsByIdResponseData(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetListsByIdResponseIncludes(BaseModel): - """Nested model for GetListsByIdResponseIncludes""" +class GetByIdResponseIncludes(BaseModel): + """Nested model for GetByIdResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -154,11 +80,11 @@ class GetListsByIdResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for updateLists +# Models for update -class UpdateListsRequest(BaseModel): - """Request model for updateLists""" +class UpdateRequest(BaseModel): + """Request model for update""" description: Optional[str] = None name: Optional[str] = None @@ -167,59 +93,59 @@ class UpdateListsRequest(BaseModel): model_config = ConfigDict(populate_by_name=True) -class UpdateListsResponse(BaseModel): - """Response model for updateLists""" +class UpdateResponse(BaseModel): + """Response model for update""" - data: Optional["UpdateListsResponseData"] = None + data: Optional["UpdateResponseData"] = None errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class UpdateListsResponseData(BaseModel): - """Nested model for UpdateListsResponseData""" +class UpdateResponseData(BaseModel): + """Nested model for UpdateResponseData""" updated: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -# Models for deleteLists +# Models for delete -class DeleteListsResponse(BaseModel): - """Response model for deleteLists""" +class DeleteResponse(BaseModel): + """Response model for delete""" - data: Optional["DeleteListsResponseData"] = None + data: Optional["DeleteResponseData"] = None errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class DeleteListsResponseData(BaseModel): - """Nested model for DeleteListsResponseData""" +class DeleteResponseData(BaseModel): + """Nested model for DeleteResponseData""" deleted: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -# Models for getUsersPinnedLists +# Models for get_members -class GetUsersPinnedListsResponse(BaseModel): - """Response model for getUsersPinnedLists""" +class GetMembersResponse(BaseModel): + """Response model for get_members""" data: Optional[List] = None errors: Optional[List] = None - includes: Optional["GetUsersPinnedListsResponseIncludes"] = None - meta: Optional["GetUsersPinnedListsResponseMeta"] = None + includes: Optional["GetMembersResponseIncludes"] = None + meta: Optional["GetMembersResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersPinnedListsResponseIncludes(BaseModel): - """Nested model for GetUsersPinnedListsResponseIncludes""" +class GetMembersResponseIncludes(BaseModel): + """Nested model for GetMembersResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -231,98 +157,154 @@ class GetUsersPinnedListsResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetUsersPinnedListsResponseMeta(BaseModel): - """Nested model for GetUsersPinnedListsResponseMeta""" +class GetMembersResponseMeta(BaseModel): + """Nested model for GetMembersResponseMeta""" + next_token: Optional[str] = None + previous_token: Optional[str] = None result_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -# Models for pinList +# Models for add_member -class PinListRequest(BaseModel): - """Request model for pinList""" +class AddMemberRequest(BaseModel): + """Request model for add_member""" - list_id: Optional[str] = None + user_id: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class PinListResponse(BaseModel): - """Response model for pinList""" +class AddMemberResponse(BaseModel): + """Response model for add_member""" - data: Optional["PinListResponseData"] = None + data: Optional["AddMemberResponseData"] = None errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class PinListResponseData(BaseModel): - """Nested model for PinListResponseData""" +class AddMemberResponseData(BaseModel): + """Nested model for AddMemberResponseData""" - pinned: Optional[bool] = None + is_member: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -# Models for unpinList +# Models for get_followers -class UnpinListResponse(BaseModel): - """Response model for unpinList""" +class GetFollowersResponse(BaseModel): + """Response model for get_followers""" - data: Optional["UnpinListResponseData"] = None + data: Optional[List] = None errors: Optional[List] = None + includes: Optional["GetFollowersResponseIncludes"] = None + meta: Optional["GetFollowersResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class UnpinListResponseData(BaseModel): - """Nested model for UnpinListResponseData""" +class GetFollowersResponseIncludes(BaseModel): + """Nested model for GetFollowersResponseIncludes""" + + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) - pinned: Optional[bool] = None + +class GetFollowersResponseMeta(BaseModel): + """Nested model for GetFollowersResponseMeta""" + + next_token: Optional[str] = None + previous_token: Optional[str] = None + result_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -# Models for removeListsMemberByUserId +# Models for get_posts -class RemoveListsMemberByUserIdResponse(BaseModel): - """Response model for removeListsMemberByUserId""" +class GetPostsResponse(BaseModel): + """Response model for get_posts""" - data: Optional["RemoveListsMemberByUserIdResponseData"] = None + data: Optional[List] = None errors: Optional[List] = None + includes: Optional["GetPostsResponseIncludes"] = None + meta: Optional["GetPostsResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class RemoveListsMemberByUserIdResponseData(BaseModel): - """Nested model for RemoveListsMemberByUserIdResponseData""" +class GetPostsResponseIncludes(BaseModel): + """Nested model for GetPostsResponseIncludes""" - is_member: Optional[bool] = None + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -# Models for getUsersOwnedLists +class GetPostsResponseMeta(BaseModel): + """Nested model for GetPostsResponseMeta""" + + next_token: Optional[str] = None + previous_token: Optional[str] = None + result_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) + +# Models for unfollow_list -class GetUsersOwnedListsResponse(BaseModel): - """Response model for getUsersOwnedLists""" + +class UnfollowListResponse(BaseModel): + """Response model for unfollow_list""" + + data: Optional["UnfollowListResponseData"] = None + errors: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class UnfollowListResponseData(BaseModel): + """Nested model for UnfollowListResponseData""" + + following: Optional[bool] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for get_users_pinned + + +class GetUsersPinnedResponse(BaseModel): + """Response model for get_users_pinned""" data: Optional[List] = None errors: Optional[List] = None - includes: Optional["GetUsersOwnedListsResponseIncludes"] = None - meta: Optional["GetUsersOwnedListsResponseMeta"] = None + includes: Optional["GetUsersPinnedResponseIncludes"] = None + meta: Optional["GetUsersPinnedResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersOwnedListsResponseIncludes(BaseModel): - """Nested model for GetUsersOwnedListsResponseIncludes""" +class GetUsersPinnedResponseIncludes(BaseModel): + """Nested model for GetUsersPinnedResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -334,21 +316,47 @@ class GetUsersOwnedListsResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetUsersOwnedListsResponseMeta(BaseModel): - """Nested model for GetUsersOwnedListsResponseMeta""" +class GetUsersPinnedResponseMeta(BaseModel): + """Nested model for GetUsersPinnedResponseMeta""" - next_token: Optional[str] = None - previous_token: Optional[str] = None result_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -# Models for createLists +# Models for pin_list -class CreateListsRequest(BaseModel): - """Request model for createLists""" +class PinListRequest(BaseModel): + """Request model for pin_list""" + + list_id: Optional[str] = None + + model_config = ConfigDict(populate_by_name=True) + + +class PinListResponse(BaseModel): + """Response model for pin_list""" + + data: Optional["PinListResponseData"] = None + errors: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class PinListResponseData(BaseModel): + """Nested model for PinListResponseData""" + + pinned: Optional[bool] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for create + + +class CreateRequest(BaseModel): + """Request model for create""" description: Optional[str] = None name: Optional[str] = None @@ -357,10 +365,10 @@ class CreateListsRequest(BaseModel): model_config = ConfigDict(populate_by_name=True) -class CreateListsResponse(BaseModel): - """Response model for createLists""" +class CreateResponse(BaseModel): + """Response model for create""" - data: Optional["CreateListsResponseData"] = Field( + data: Optional["CreateResponseData"] = Field( description="A X List is a curated group of accounts.", default_factory=dict ) errors: Optional[List] = None @@ -368,8 +376,8 @@ class CreateListsResponse(BaseModel): model_config = ConfigDict(populate_by_name=True) -class CreateListsResponseData(BaseModel): - """Nested model for CreateListsResponseData""" +class CreateResponseData(BaseModel): + """Nested model for CreateResponseData""" id: Optional[str] = None name: Optional[str] = None @@ -377,49 +385,41 @@ class CreateListsResponseData(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for addListsMember - - -class AddListsMemberRequest(BaseModel): - """Request model for addListsMember""" - - user_id: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) +# Models for remove_member_by_user_id -class AddListsMemberResponse(BaseModel): - """Response model for addListsMember""" +class RemoveMemberByUserIdResponse(BaseModel): + """Response model for remove_member_by_user_id""" - data: Optional["AddListsMemberResponseData"] = None + data: Optional["RemoveMemberByUserIdResponseData"] = None errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class AddListsMemberResponseData(BaseModel): - """Nested model for AddListsMemberResponseData""" +class RemoveMemberByUserIdResponseData(BaseModel): + """Nested model for RemoveMemberByUserIdResponseData""" is_member: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -# Models for unfollowList +# Models for unpin_list -class UnfollowListResponse(BaseModel): - """Response model for unfollowList""" +class UnpinListResponse(BaseModel): + """Response model for unpin_list""" - data: Optional["UnfollowListResponseData"] = None + data: Optional["UnpinListResponseData"] = None errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class UnfollowListResponseData(BaseModel): - """Nested model for UnfollowListResponseData""" +class UnpinListResponseData(BaseModel): + """Nested model for UnpinListResponseData""" - following: Optional[bool] = None + pinned: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) diff --git a/xdk/python/xdk/media/__init__.py b/xdk/python/xdk/media/__init__.py index 74910c78..03b53e2c 100644 --- a/xdk/python/xdk/media/__init__.py +++ b/xdk/python/xdk/media/__init__.py @@ -1,7 +1,7 @@ """ -Media module for the X API. +media module for the X API. -This module provides access to the Media endpoints of the X API. +This module provides access to the media endpoints of the X API. """ from .client import MediaClient diff --git a/xdk/python/xdk/media/client.py b/xdk/python/xdk/media/client.py index 20511a9b..19404581 100644 --- a/xdk/python/xdk/media/client.py +++ b/xdk/python/xdk/media/client.py @@ -1,7 +1,7 @@ """ -Media client for the X API. +media client for the X API. -This module provides a client for interacting with the Media endpoints of the X API. +This module provides a client for interacting with the media endpoints of the X API. """ from __future__ import annotations @@ -12,46 +12,46 @@ if TYPE_CHECKING: from ..client import Client from .models import ( - CreateMediaMetadataRequest, - CreateMediaMetadataResponse, - CreateMediaSubtitlesRequest, - CreateMediaSubtitlesResponse, - DeleteMediaSubtitlesRequest, - DeleteMediaSubtitlesResponse, - GetMediaUploadStatusResponse, - MediaUploadRequest, - MediaUploadResponse, - InitializeMediaUploadRequest, - InitializeMediaUploadResponse, - GetMediaAnalyticsResponse, - GetMediaByMediaKeysResponse, - GetMediaByMediaKeyResponse, - FinalizeMediaUploadResponse, - AppendMediaUploadRequest, - AppendMediaUploadResponse, + InitializeUploadRequest, + InitializeUploadResponse, + CreateSubtitlesRequest, + CreateSubtitlesResponse, + DeleteSubtitlesRequest, + DeleteSubtitlesResponse, + AppendUploadRequest, + AppendUploadResponse, + GetUploadStatusResponse, + UploadRequest, + UploadResponse, + FinalizeUploadResponse, + GetAnalyticsResponse, + GetByKeyResponse, + CreateMetadataRequest, + CreateMetadataResponse, + GetByKeysResponse, ) class MediaClient: - """Client for Media operations""" + """Client for media operations""" def __init__(self, client: Client): self.client = client - def create_media_metadata( + def initialize_upload( self, - body: Optional[CreateMediaMetadataRequest] = None, - ) -> CreateMediaMetadataResponse: + body: Optional[InitializeUploadRequest] = None, + ) -> InitializeUploadResponse: """ - Create Media metadata - Creates metadata for a Media file. + Initialize media upload + Initializes a media upload. body: Request body Returns: - CreateMediaMetadataResponse: Response data + InitializeUploadResponse: Response data """ - url = self.client.base_url + "/2/media/metadata" + url = self.client.base_url + "/2/media/upload/initialize" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh @@ -80,19 +80,19 @@ def create_media_metadata( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return CreateMediaMetadataResponse.model_validate(response_data) + return InitializeUploadResponse.model_validate(response_data) - def create_media_subtitles( + def create_subtitles( self, - body: Optional[CreateMediaSubtitlesRequest] = None, - ) -> CreateMediaSubtitlesResponse: + body: Optional[CreateSubtitlesRequest] = None, + ) -> CreateSubtitlesResponse: """ Create Media subtitles Creates subtitles for a specific Media file. body: Request body Returns: - CreateMediaSubtitlesResponse: Response data + CreateSubtitlesResponse: Response data """ url = self.client.base_url + "/2/media/subtitles" # Ensure we have a valid access token @@ -123,19 +123,19 @@ def create_media_subtitles( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return CreateMediaSubtitlesResponse.model_validate(response_data) + return CreateSubtitlesResponse.model_validate(response_data) - def delete_media_subtitles( + def delete_subtitles( self, - body: Optional[DeleteMediaSubtitlesRequest] = None, - ) -> DeleteMediaSubtitlesResponse: + body: Optional[DeleteSubtitlesRequest] = None, + ) -> DeleteSubtitlesResponse: """ Delete Media subtitles Deletes subtitles for a specific Media file. body: Request body Returns: - DeleteMediaSubtitlesResponse: Response data + DeleteSubtitlesResponse: Response data """ url = self.client.base_url + "/2/media/subtitles" # Ensure we have a valid access token @@ -166,14 +166,61 @@ def delete_media_subtitles( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return DeleteMediaSubtitlesResponse.model_validate(response_data) + return DeleteSubtitlesResponse.model_validate(response_data) - def get_media_upload_status( + def append_upload( self, - media_id: str, + id: Any, + body: Optional[AppendUploadRequest] = None, + ) -> AppendUploadResponse: + """ + Append Media upload + Appends data to a Media upload request. + Args: + id: The media identifier for the media to perform the append operation. + body: Request body + Returns: + AppendUploadResponse: Response data + """ + url = self.client.base_url + "/2/media/upload/{id}/append" + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + url = url.replace("{id}", str(id)) + headers = {} + headers["Content-Type"] = "application/json" + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.post( + url, + params=params, + headers=headers, + json=body.model_dump(exclude_none=True) if body else None, + ) + else: + response = self.client.session.post( + url, + params=params, + headers=headers, + json=body.model_dump(exclude_none=True) if body else None, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return AppendUploadResponse.model_validate(response_data) + + + def get_upload_status( + self, + media_id: Any, command: str = None, - ) -> GetMediaUploadStatusResponse: + ) -> GetUploadStatusResponse: """ Get Media upload status Retrieves the status of a Media upload by its ID. @@ -182,7 +229,7 @@ def get_media_upload_status( Args: command: The command for the media upload request. Returns: - GetMediaUploadStatusResponse: Response data + GetUploadStatusResponse: Response data """ url = self.client.base_url + "/2/media/upload" # Ensure we have a valid access token @@ -214,19 +261,19 @@ def get_media_upload_status( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetMediaUploadStatusResponse.model_validate(response_data) + return GetUploadStatusResponse.model_validate(response_data) - def media_upload( + def upload( self, - body: Optional[MediaUploadRequest] = None, - ) -> MediaUploadResponse: + body: Optional[UploadRequest] = None, + ) -> UploadResponse: """ Upload media Uploads a media file for use in posts or other content. body: Request body Returns: - MediaUploadResponse: Response data + UploadResponse: Response data """ url = self.client.base_url + "/2/media/upload" # Ensure we have a valid access token @@ -257,60 +304,58 @@ def media_upload( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return MediaUploadResponse.model_validate(response_data) + return UploadResponse.model_validate(response_data) - def initialize_media_upload( + def finalize_upload( self, - body: Optional[InitializeMediaUploadRequest] = None, - ) -> InitializeMediaUploadResponse: + id: Any, + ) -> FinalizeUploadResponse: """ - Initialize media upload - Initializes a media upload. - body: Request body + Finalize Media upload + Finalizes a Media upload request. + Args: + id: The media id of the targeted media to finalize. Returns: - InitializeMediaUploadResponse: Response data + FinalizeUploadResponse: Response data """ - url = self.client.base_url + "/2/media/upload/initialize" + url = self.client.base_url + "/2/media/upload/{id}/finalize" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} + url = url.replace("{id}", str(id)) headers = {} - headers["Content-Type"] = "application/json" # Make the request if self.client.oauth2_session: response = self.client.oauth2_session.post( url, params=params, headers=headers, - json=body.model_dump(exclude_none=True) if body else None, ) else: response = self.client.session.post( url, params=params, headers=headers, - json=body.model_dump(exclude_none=True) if body else None, ) # Check for errors response.raise_for_status() # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return InitializeMediaUploadResponse.model_validate(response_data) + return FinalizeUploadResponse.model_validate(response_data) - def get_media_analytics( + def get_analytics( self, media_keys: List, end_time: str, start_time: str, granularity: str, - media_analytics_fields: List = None, - ) -> GetMediaAnalyticsResponse: + ) -> GetAnalyticsResponse: """ Get Media analytics Retrieves analytics data for media. @@ -322,10 +367,8 @@ def get_media_analytics( start_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range. Args: granularity: The granularity for the search counts results. - Args: - media_analytics_fields: A comma separated list of MediaAnalytics fields to display. Returns: - GetMediaAnalyticsResponse: Response data + GetAnalyticsResponse: Response data """ url = self.client.base_url + "/2/media/analytics" # Ensure we have a valid access token @@ -342,10 +385,6 @@ def get_media_analytics( params["start_time"] = start_time if granularity is not None: params["granularity"] = granularity - if media_analytics_fields is not None: - params["media_analytics.fields"] = ",".join( - str(item) for item in media_analytics_fields - ) headers = {} # Make the request if self.client.oauth2_session: @@ -365,72 +404,20 @@ def get_media_analytics( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetMediaAnalyticsResponse.model_validate(response_data) - - - def get_media_by_media_keys( - self, - media_keys: List, - media_fields: List = None, - ) -> GetMediaByMediaKeysResponse: - """ - Get Media by media keys - Retrieves details of Media files by their media keys. - Args: - media_keys: A comma separated list of Media Keys. Up to 100 are allowed in a single request. - Args: - media_fields: A comma separated list of Media fields to display. - Returns: - GetMediaByMediaKeysResponse: Response data - """ - url = self.client.base_url + "/2/media" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if media_keys is not None: - params["media_keys"] = ",".join(str(item) for item in media_keys) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetMediaByMediaKeysResponse.model_validate(response_data) + return GetAnalyticsResponse.model_validate(response_data) - def get_media_by_media_key( + def get_by_key( self, - media_key: str, - media_fields: List = None, - ) -> GetMediaByMediaKeyResponse: + media_key: Any, + ) -> GetByKeyResponse: """ Get Media by media key Retrieves details of a specific Media file by its media key. Args: media_key: A single Media Key. - Args: - media_fields: A comma separated list of Media fields to display. Returns: - GetMediaByMediaKeyResponse: Response data + GetByKeyResponse: Response data """ url = self.client.base_url + "/2/media/{media_key}" if self.client.bearer_token: @@ -447,8 +434,6 @@ def get_media_by_media_key( if self.client.is_token_expired(): self.client.refresh_token() params = {} - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) url = url.replace("{media_key}", str(media_key)) headers = {} # Make the request @@ -462,93 +447,91 @@ def get_media_by_media_key( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetMediaByMediaKeyResponse.model_validate(response_data) + return GetByKeyResponse.model_validate(response_data) - def finalize_media_upload( + def create_metadata( self, - id: str, - ) -> FinalizeMediaUploadResponse: + body: Optional[CreateMetadataRequest] = None, + ) -> CreateMetadataResponse: """ - Finalize Media upload - Finalizes a Media upload request. - Args: - id: The media id of the targeted media to finalize. + Create Media metadata + Creates metadata for a Media file. + body: Request body Returns: - FinalizeMediaUploadResponse: Response data + CreateMetadataResponse: Response data """ - url = self.client.base_url + "/2/media/upload/{id}/finalize" + url = self.client.base_url + "/2/media/metadata" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} - url = url.replace("{id}", str(id)) headers = {} + headers["Content-Type"] = "application/json" # Make the request if self.client.oauth2_session: response = self.client.oauth2_session.post( url, params=params, headers=headers, + json=body.model_dump(exclude_none=True) if body else None, ) else: response = self.client.session.post( url, params=params, headers=headers, + json=body.model_dump(exclude_none=True) if body else None, ) # Check for errors response.raise_for_status() # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return FinalizeMediaUploadResponse.model_validate(response_data) + return CreateMetadataResponse.model_validate(response_data) - def append_media_upload( + def get_by_keys( self, - id: str, - body: Optional[AppendMediaUploadRequest] = None, - ) -> AppendMediaUploadResponse: + media_keys: List, + ) -> GetByKeysResponse: """ - Append Media upload - Appends data to a Media upload request. + Get Media by media keys + Retrieves details of Media files by their media keys. Args: - id: The media identifier for the media to perform the append operation. - body: Request body + media_keys: A comma separated list of Media Keys. Up to 100 are allowed in a single request. Returns: - AppendMediaUploadResponse: Response data + GetByKeysResponse: Response data """ - url = self.client.base_url + "/2/media/upload/{id}/append" + url = self.client.base_url + "/2/media" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} - url = url.replace("{id}", str(id)) + if media_keys is not None: + params["media_keys"] = ",".join(str(item) for item in media_keys) headers = {} - headers["Content-Type"] = "application/json" # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) + response = self.client.session.get( + url, + params=params, + headers=headers, + ) # Check for errors response.raise_for_status() # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return AppendMediaUploadResponse.model_validate(response_data) + return GetByKeysResponse.model_validate(response_data) diff --git a/xdk/python/xdk/media/models.py b/xdk/python/xdk/media/models.py index 36d7e830..55383efd 100644 --- a/xdk/python/xdk/media/models.py +++ b/xdk/python/xdk/media/models.py @@ -1,7 +1,7 @@ """ -Media models for the X API. +media models for the X API. -This module provides models for the Media endpoints of the X API. +This module provides models for the media endpoints of the X API. """ from typing import Dict, List, Optional, Any, Union, Literal @@ -9,637 +9,631 @@ from datetime import datetime -# Models for createMediaMetadata +# Models for initialize_upload -class CreateMediaMetadataRequest(BaseModel): - """Request model for createMediaMetadata""" +class InitializeUploadRequest(BaseModel): + """Request model for initialize_upload""" - id: Optional[str] = None - metadata: Optional["CreateMediaMetadataRequestMetadata"] = None + additional_owners: Optional[List] = None + media_category: Optional[str] = None + media_type: Optional[str] = None + shared: Optional[bool] = None + total_bytes: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataResponse(BaseModel): - """Response model for createMediaMetadata""" +class InitializeUploadResponse(BaseModel): + """Response model for initialize_upload""" - data: Optional["CreateMediaMetadataResponseData"] = None + data: Optional["InitializeUploadResponseData"] = Field(default_factory=dict) errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataRequestMetadata(BaseModel): - """Nested model for CreateMediaMetadataRequestMetadata""" +class InitializeUploadResponseData(BaseModel): + """Nested model for InitializeUploadResponseData""" - allow_download_status: Optional[ - "CreateMediaMetadataRequestMetadataAllowDownloadStatus" - ] = None - alt_text: Optional["CreateMediaMetadataRequestMetadataAltText"] = None - audience_policy: Optional["CreateMediaMetadataRequestMetadataAudiencePolicy"] = None - content_expiration: Optional[ - "CreateMediaMetadataRequestMetadataContentExpiration" - ] = None - domain_restrictions: Optional[ - "CreateMediaMetadataRequestMetadataDomainRestrictions" - ] = None - found_media_origin: Optional[ - "CreateMediaMetadataRequestMetadataFoundMediaOrigin" - ] = None - geo_restrictions: Any = None - management_info: Optional["CreateMediaMetadataRequestMetadataManagementInfo"] = None - preview_image: Optional["CreateMediaMetadataRequestMetadataPreviewImage"] = None - sensitive_media_warning: Optional[ - "CreateMediaMetadataRequestMetadataSensitiveMediaWarning" - ] = None - shared_info: Optional["CreateMediaMetadataRequestMetadataSharedInfo"] = None - sticker_info: Optional["CreateMediaMetadataRequestMetadataStickerInfo"] = None - upload_source: Optional["CreateMediaMetadataRequestMetadataUploadSource"] = None + expires_after_secs: Optional[int] = None + id: Optional[str] = None + media_key: Optional[str] = None + processing_info: Optional["InitializeUploadResponseDataProcessingInfo"] = None + size: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataRequestMetadataAllowDownloadStatus(BaseModel): - """Nested model for CreateMediaMetadataRequestMetadataAllowDownloadStatus""" +class InitializeUploadResponseDataProcessingInfo(BaseModel): + """Nested model for InitializeUploadResponseDataProcessingInfo""" - allow_download: Optional[bool] = None + check_after_secs: Optional[int] = None + progress_percent: Optional[int] = None + state: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataRequestMetadataAltText(BaseModel): - """Nested model for CreateMediaMetadataRequestMetadataAltText""" +# Models for create_subtitles - text: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) +class CreateSubtitlesRequest(BaseModel): + """Request model for create_subtitles""" -class CreateMediaMetadataRequestMetadataAudiencePolicy(BaseModel): - """Nested model for CreateMediaMetadataRequestMetadataAudiencePolicy""" - - creator_subscriptions: Optional[List] = None - x_subscriptions: Optional[List] = None + id: Optional[str] = None + media_category: Optional[str] = None + subtitles: Optional["CreateSubtitlesRequestSubtitles"] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataRequestMetadataContentExpiration(BaseModel): - """Nested model for CreateMediaMetadataRequestMetadataContentExpiration""" +class CreateSubtitlesResponse(BaseModel): + """Response model for create_subtitles""" - timestamp_sec: Optional[float] = None + data: Optional["CreateSubtitlesResponseData"] = Field(default_factory=dict) + errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataRequestMetadataDomainRestrictions(BaseModel): - """Nested model for CreateMediaMetadataRequestMetadataDomainRestrictions""" +class CreateSubtitlesRequestSubtitles(BaseModel): + """Nested model for CreateSubtitlesRequestSubtitles""" - whitelist: Optional[List] = None + display_name: Optional[str] = None + id: Optional[str] = None + language_code: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataRequestMetadataFoundMediaOrigin(BaseModel): - """Nested model for CreateMediaMetadataRequestMetadataFoundMediaOrigin""" +class CreateSubtitlesResponseData(BaseModel): + """Nested model for CreateSubtitlesResponseData""" + associated_subtitles: Optional[List] = None id: Optional[str] = None - provider: Optional[str] = None + media_category: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataRequestMetadataManagementInfo(BaseModel): - """Nested model for CreateMediaMetadataRequestMetadataManagementInfo""" +# Models for delete_subtitles - managed: Optional[bool] = None + +class DeleteSubtitlesRequest(BaseModel): + """Request model for delete_subtitles""" + + id: Optional[str] = None + language_code: Optional[str] = None + media_category: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataRequestMetadataPreviewImage(BaseModel): - """Nested model for CreateMediaMetadataRequestMetadataPreviewImage""" +class DeleteSubtitlesResponse(BaseModel): + """Response model for delete_subtitles""" - media_key: Optional["CreateMediaMetadataRequestMetadataPreviewImageMediaKey"] = None + data: Optional["DeleteSubtitlesResponseData"] = Field(default_factory=dict) + errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataRequestMetadataPreviewImageMediaKey(BaseModel): - """Nested model for CreateMediaMetadataRequestMetadataPreviewImageMediaKey""" +class DeleteSubtitlesResponseData(BaseModel): + """Nested model for DeleteSubtitlesResponseData""" - media: Optional[str] = None - media_category: Optional[str] = None + deleted: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataRequestMetadataSensitiveMediaWarning(BaseModel): - """Nested model for CreateMediaMetadataRequestMetadataSensitiveMediaWarning""" +# Models for append_upload - adult_content: Optional[bool] = None - graphic_violence: Optional[bool] = None - other: Optional[bool] = None + +class AppendUploadRequest(BaseModel): + """Request model for append_upload""" + + media: Optional[str] = Field(default=None, description="The file to upload.") + segment_index: Optional[Any] = Field(default=None) + media: Optional[str] = Field(default=None, description="The file to upload.") + segment_index: Optional[Any] = Field(default=None) model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataRequestMetadataSharedInfo(BaseModel): - """Nested model for CreateMediaMetadataRequestMetadataSharedInfo""" +class AppendUploadResponse(BaseModel): + """Response model for append_upload""" - shared: Optional[bool] = None + data: Optional["AppendUploadResponseData"] = None + errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataRequestMetadataStickerInfo(BaseModel): - """Nested model for CreateMediaMetadataRequestMetadataStickerInfo""" +class AppendUploadResponseData(BaseModel): + """Nested model for AppendUploadResponseData""" - stickers: Optional[List] = None + expires_at: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataRequestMetadataUploadSource(BaseModel): - """Nested model for CreateMediaMetadataRequestMetadataUploadSource""" +# Models for get_upload_status - upload_source: Optional[str] = None + +class GetUploadStatusResponse(BaseModel): + """Response model for get_upload_status""" + + data: Optional["GetUploadStatusResponseData"] = Field(default_factory=dict) + errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataResponseData(BaseModel): - """Nested model for CreateMediaMetadataResponseData""" +class GetUploadStatusResponseData(BaseModel): + """Nested model for GetUploadStatusResponseData""" - associated_metadata: Optional[ - "CreateMediaMetadataResponseDataAssociatedMetadata" - ] = None + expires_after_secs: Optional[int] = None id: Optional[str] = None + media_key: Optional[str] = None + processing_info: Optional["GetUploadStatusResponseDataProcessingInfo"] = None + size: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataResponseDataAssociatedMetadata(BaseModel): - """Nested model for CreateMediaMetadataResponseDataAssociatedMetadata""" +class GetUploadStatusResponseDataProcessingInfo(BaseModel): + """Nested model for GetUploadStatusResponseDataProcessingInfo""" - allow_download_status: Optional[ - "CreateMediaMetadataResponseDataAssociatedMetadataAllowDownloadStatus" - ] = None - alt_text: Optional["CreateMediaMetadataResponseDataAssociatedMetadataAltText"] = ( - None - ) - audience_policy: Optional[ - "CreateMediaMetadataResponseDataAssociatedMetadataAudiencePolicy" - ] = None - content_expiration: Optional[ - "CreateMediaMetadataResponseDataAssociatedMetadataContentExpiration" - ] = None - domain_restrictions: Optional[ - "CreateMediaMetadataResponseDataAssociatedMetadataDomainRestrictions" - ] = None - found_media_origin: Optional[ - "CreateMediaMetadataResponseDataAssociatedMetadataFoundMediaOrigin" - ] = None - geo_restrictions: Any = None - management_info: Optional[ - "CreateMediaMetadataResponseDataAssociatedMetadataManagementInfo" - ] = None - preview_image: Optional[ - "CreateMediaMetadataResponseDataAssociatedMetadataPreviewImage" - ] = None - sensitive_media_warning: Optional[ - "CreateMediaMetadataResponseDataAssociatedMetadataSensitiveMediaWarning" - ] = None - shared_info: Optional[ - "CreateMediaMetadataResponseDataAssociatedMetadataSharedInfo" - ] = None - sticker_info: Optional[ - "CreateMediaMetadataResponseDataAssociatedMetadataStickerInfo" - ] = None - upload_source: Optional[ - "CreateMediaMetadataResponseDataAssociatedMetadataUploadSource" - ] = None + check_after_secs: Optional[int] = None + progress_percent: Optional[int] = None + state: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataResponseDataAssociatedMetadataAllowDownloadStatus(BaseModel): - """Nested model for CreateMediaMetadataResponseDataAssociatedMetadataAllowDownloadStatus""" - - allow_download: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) +# Models for upload -class CreateMediaMetadataResponseDataAssociatedMetadataAltText(BaseModel): - """Nested model for CreateMediaMetadataResponseDataAssociatedMetadataAltText""" +class UploadRequest(BaseModel): + """Request model for upload""" - text: Optional[str] = None + additional_owners: Optional[List] = None + media: Any = None + media_category: Optional[str] = None + media_type: Optional[str] = None + shared: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataResponseDataAssociatedMetadataAudiencePolicy(BaseModel): - """Nested model for CreateMediaMetadataResponseDataAssociatedMetadataAudiencePolicy""" +class UploadResponse(BaseModel): + """Response model for upload""" - creator_subscriptions: Optional[List] = None - x_subscriptions: Optional[List] = None + data: Optional["UploadResponseData"] = Field(default_factory=dict) + errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataResponseDataAssociatedMetadataContentExpiration(BaseModel): - """Nested model for CreateMediaMetadataResponseDataAssociatedMetadataContentExpiration""" +class UploadResponseData(BaseModel): + """Nested model for UploadResponseData""" - timestamp_sec: Optional[float] = None + expires_after_secs: Optional[int] = None + id: Optional[str] = None + media_key: Optional[str] = None + processing_info: Optional["UploadResponseDataProcessingInfo"] = None + size: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataResponseDataAssociatedMetadataDomainRestrictions(BaseModel): - """Nested model for CreateMediaMetadataResponseDataAssociatedMetadataDomainRestrictions""" +class UploadResponseDataProcessingInfo(BaseModel): + """Nested model for UploadResponseDataProcessingInfo""" - whitelist: Optional[List] = None + check_after_secs: Optional[int] = None + progress_percent: Optional[int] = None + state: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataResponseDataAssociatedMetadataFoundMediaOrigin(BaseModel): - """Nested model for CreateMediaMetadataResponseDataAssociatedMetadataFoundMediaOrigin""" - - id: Optional[str] = None - provider: Optional[str] = None +# Models for finalize_upload - model_config = ConfigDict(populate_by_name=True) +class FinalizeUploadResponse(BaseModel): + """Response model for finalize_upload""" -class CreateMediaMetadataResponseDataAssociatedMetadataManagementInfo(BaseModel): - """Nested model for CreateMediaMetadataResponseDataAssociatedMetadataManagementInfo""" - - managed: Optional[bool] = None + data: Optional["FinalizeUploadResponseData"] = Field(default_factory=dict) + errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataResponseDataAssociatedMetadataPreviewImage(BaseModel): - """Nested model for CreateMediaMetadataResponseDataAssociatedMetadataPreviewImage""" +class FinalizeUploadResponseData(BaseModel): + """Nested model for FinalizeUploadResponseData""" - media_key: Optional[ - "CreateMediaMetadataResponseDataAssociatedMetadataPreviewImageMediaKey" - ] = None + expires_after_secs: Optional[int] = None + id: Optional[str] = None + media_key: Optional[str] = None + processing_info: Optional["FinalizeUploadResponseDataProcessingInfo"] = None + size: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataResponseDataAssociatedMetadataPreviewImageMediaKey(BaseModel): - """Nested model for CreateMediaMetadataResponseDataAssociatedMetadataPreviewImageMediaKey""" +class FinalizeUploadResponseDataProcessingInfo(BaseModel): + """Nested model for FinalizeUploadResponseDataProcessingInfo""" - media: Optional[str] = None - media_category: Optional[str] = None + check_after_secs: Optional[int] = None + progress_percent: Optional[int] = None + state: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataResponseDataAssociatedMetadataSensitiveMediaWarning(BaseModel): - """Nested model for CreateMediaMetadataResponseDataAssociatedMetadataSensitiveMediaWarning""" +# Models for get_analytics - adult_content: Optional[bool] = None - graphic_violence: Optional[bool] = None - other: Optional[bool] = None - model_config = ConfigDict(populate_by_name=True) +class GetAnalyticsResponse(BaseModel): + """Response model for get_analytics""" + data: Optional[List] = None + errors: Optional[List] = None -class CreateMediaMetadataResponseDataAssociatedMetadataSharedInfo(BaseModel): - """Nested model for CreateMediaMetadataResponseDataAssociatedMetadataSharedInfo""" + model_config = ConfigDict(populate_by_name=True) - shared: Optional[bool] = None - model_config = ConfigDict(populate_by_name=True) +# Models for get_by_key -class CreateMediaMetadataResponseDataAssociatedMetadataStickerInfo(BaseModel): - """Nested model for CreateMediaMetadataResponseDataAssociatedMetadataStickerInfo""" +class GetByKeyResponse(BaseModel): + """Response model for get_by_key""" - stickers: Optional[List] = None + data: Optional["GetByKeyResponseData"] = Field(default_factory=dict) + errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaMetadataResponseDataAssociatedMetadataUploadSource(BaseModel): - """Nested model for CreateMediaMetadataResponseDataAssociatedMetadataUploadSource""" +class GetByKeyResponseData(BaseModel): + """Nested model for GetByKeyResponseData""" - upload_source: Optional[str] = None + height: Optional[int] = None + media_key: Optional[str] = None + type: Optional[str] = None + width: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -# Models for createMediaSubtitles +# Models for create_metadata -class CreateMediaSubtitlesRequest(BaseModel): - """Request model for createMediaSubtitles""" +class CreateMetadataRequest(BaseModel): + """Request model for create_metadata""" id: Optional[str] = None - media_category: Optional[str] = None - subtitles: Optional["CreateMediaSubtitlesRequestSubtitles"] = None + metadata: Optional["CreateMetadataRequestMetadata"] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaSubtitlesResponse(BaseModel): - """Response model for createMediaSubtitles""" +class CreateMetadataResponse(BaseModel): + """Response model for create_metadata""" - data: Optional["CreateMediaSubtitlesResponseData"] = Field(default_factory=dict) + data: Optional["CreateMetadataResponseData"] = None errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaSubtitlesRequestSubtitles(BaseModel): - """Nested model for CreateMediaSubtitlesRequestSubtitles""" +class CreateMetadataRequestMetadata(BaseModel): + """Nested model for CreateMetadataRequestMetadata""" - display_name: Optional[str] = None - id: Optional[str] = None - language_code: Optional[str] = None + allow_download_status: Optional[ + "CreateMetadataRequestMetadataAllowDownloadStatus" + ] = None + alt_text: Optional["CreateMetadataRequestMetadataAltText"] = None + audience_policy: Optional["CreateMetadataRequestMetadataAudiencePolicy"] = None + content_expiration: Optional["CreateMetadataRequestMetadataContentExpiration"] = ( + None + ) + domain_restrictions: Optional["CreateMetadataRequestMetadataDomainRestrictions"] = ( + None + ) + found_media_origin: Optional["CreateMetadataRequestMetadataFoundMediaOrigin"] = None + geo_restrictions: Any = None + management_info: Optional["CreateMetadataRequestMetadataManagementInfo"] = None + preview_image: Optional["CreateMetadataRequestMetadataPreviewImage"] = None + sensitive_media_warning: Optional[ + "CreateMetadataRequestMetadataSensitiveMediaWarning" + ] = None + shared_info: Optional["CreateMetadataRequestMetadataSharedInfo"] = None + sticker_info: Optional["CreateMetadataRequestMetadataStickerInfo"] = None + upload_source: Optional["CreateMetadataRequestMetadataUploadSource"] = None model_config = ConfigDict(populate_by_name=True) -class CreateMediaSubtitlesResponseData(BaseModel): - """Nested model for CreateMediaSubtitlesResponseData""" +class CreateMetadataRequestMetadataAllowDownloadStatus(BaseModel): + """Nested model for CreateMetadataRequestMetadataAllowDownloadStatus""" - associated_subtitles: Optional[List] = None - id: Optional[str] = None - media_category: Optional[str] = None + allow_download: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -# Models for deleteMediaSubtitles - - -class DeleteMediaSubtitlesRequest(BaseModel): - """Request model for deleteMediaSubtitles""" +class CreateMetadataRequestMetadataAltText(BaseModel): + """Nested model for CreateMetadataRequestMetadataAltText""" - id: Optional[str] = None - language_code: Optional[str] = None - media_category: Optional[str] = None + text: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class DeleteMediaSubtitlesResponse(BaseModel): - """Response model for deleteMediaSubtitles""" +class CreateMetadataRequestMetadataAudiencePolicy(BaseModel): + """Nested model for CreateMetadataRequestMetadataAudiencePolicy""" - data: Optional["DeleteMediaSubtitlesResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None + creator_subscriptions: Optional[List] = None + x_subscriptions: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class DeleteMediaSubtitlesResponseData(BaseModel): - """Nested model for DeleteMediaSubtitlesResponseData""" +class CreateMetadataRequestMetadataContentExpiration(BaseModel): + """Nested model for CreateMetadataRequestMetadataContentExpiration""" - deleted: Optional[bool] = None + timestamp_sec: Optional[float] = None model_config = ConfigDict(populate_by_name=True) -# Models for getMediaUploadStatus - +class CreateMetadataRequestMetadataDomainRestrictions(BaseModel): + """Nested model for CreateMetadataRequestMetadataDomainRestrictions""" -class GetMediaUploadStatusResponse(BaseModel): - """Response model for getMediaUploadStatus""" - - data: Optional["GetMediaUploadStatusResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None + whitelist: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class GetMediaUploadStatusResponseData(BaseModel): - """Nested model for GetMediaUploadStatusResponseData""" +class CreateMetadataRequestMetadataFoundMediaOrigin(BaseModel): + """Nested model for CreateMetadataRequestMetadataFoundMediaOrigin""" - expires_after_secs: Optional[int] = None id: Optional[str] = None - media_key: Optional[str] = None - processing_info: Optional["GetMediaUploadStatusResponseDataProcessingInfo"] = None - size: Optional[int] = None + provider: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class GetMediaUploadStatusResponseDataProcessingInfo(BaseModel): - """Nested model for GetMediaUploadStatusResponseDataProcessingInfo""" +class CreateMetadataRequestMetadataManagementInfo(BaseModel): + """Nested model for CreateMetadataRequestMetadataManagementInfo""" - check_after_secs: Optional[int] = None - progress_percent: Optional[int] = None - state: Optional[str] = None + managed: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -# Models for mediaUpload - +class CreateMetadataRequestMetadataPreviewImage(BaseModel): + """Nested model for CreateMetadataRequestMetadataPreviewImage""" -class MediaUploadRequest(BaseModel): - """Request model for mediaUpload""" - - additional_owners: Optional[List] = None - media: Any = None - media_category: Optional[str] = None - media_type: Optional[str] = None - shared: Optional[bool] = None + media_key: Optional["CreateMetadataRequestMetadataPreviewImageMediaKey"] = None model_config = ConfigDict(populate_by_name=True) -class MediaUploadResponse(BaseModel): - """Response model for mediaUpload""" +class CreateMetadataRequestMetadataPreviewImageMediaKey(BaseModel): + """Nested model for CreateMetadataRequestMetadataPreviewImageMediaKey""" - data: Optional["MediaUploadResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None + media: Optional[str] = None + media_category: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class MediaUploadResponseData(BaseModel): - """Nested model for MediaUploadResponseData""" +class CreateMetadataRequestMetadataSensitiveMediaWarning(BaseModel): + """Nested model for CreateMetadataRequestMetadataSensitiveMediaWarning""" - expires_after_secs: Optional[int] = None - id: Optional[str] = None - media_key: Optional[str] = None - processing_info: Optional["MediaUploadResponseDataProcessingInfo"] = None - size: Optional[int] = None + adult_content: Optional[bool] = None + graphic_violence: Optional[bool] = None + other: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -class MediaUploadResponseDataProcessingInfo(BaseModel): - """Nested model for MediaUploadResponseDataProcessingInfo""" +class CreateMetadataRequestMetadataSharedInfo(BaseModel): + """Nested model for CreateMetadataRequestMetadataSharedInfo""" - check_after_secs: Optional[int] = None - progress_percent: Optional[int] = None - state: Optional[str] = None + shared: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -# Models for initializeMediaUpload +class CreateMetadataRequestMetadataStickerInfo(BaseModel): + """Nested model for CreateMetadataRequestMetadataStickerInfo""" - -class InitializeMediaUploadRequest(BaseModel): - """Request model for initializeMediaUpload""" - - additional_owners: Optional[List] = None - media_category: Optional[str] = None - media_type: Optional[str] = None - shared: Optional[bool] = None - total_bytes: Optional[int] = None + stickers: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class InitializeMediaUploadResponse(BaseModel): - """Response model for initializeMediaUpload""" +class CreateMetadataRequestMetadataUploadSource(BaseModel): + """Nested model for CreateMetadataRequestMetadataUploadSource""" - data: Optional["InitializeMediaUploadResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None + upload_source: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class InitializeMediaUploadResponseData(BaseModel): - """Nested model for InitializeMediaUploadResponseData""" +class CreateMetadataResponseData(BaseModel): + """Nested model for CreateMetadataResponseData""" - expires_after_secs: Optional[int] = None + associated_metadata: Optional["CreateMetadataResponseDataAssociatedMetadata"] = None id: Optional[str] = None - media_key: Optional[str] = None - processing_info: Optional["InitializeMediaUploadResponseDataProcessingInfo"] = None - size: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class InitializeMediaUploadResponseDataProcessingInfo(BaseModel): - """Nested model for InitializeMediaUploadResponseDataProcessingInfo""" +class CreateMetadataResponseDataAssociatedMetadata(BaseModel): + """Nested model for CreateMetadataResponseDataAssociatedMetadata""" - check_after_secs: Optional[int] = None - progress_percent: Optional[int] = None - state: Optional[str] = None + allow_download_status: Optional[ + "CreateMetadataResponseDataAssociatedMetadataAllowDownloadStatus" + ] = None + alt_text: Optional["CreateMetadataResponseDataAssociatedMetadataAltText"] = None + audience_policy: Optional[ + "CreateMetadataResponseDataAssociatedMetadataAudiencePolicy" + ] = None + content_expiration: Optional[ + "CreateMetadataResponseDataAssociatedMetadataContentExpiration" + ] = None + domain_restrictions: Optional[ + "CreateMetadataResponseDataAssociatedMetadataDomainRestrictions" + ] = None + found_media_origin: Optional[ + "CreateMetadataResponseDataAssociatedMetadataFoundMediaOrigin" + ] = None + geo_restrictions: Any = None + management_info: Optional[ + "CreateMetadataResponseDataAssociatedMetadataManagementInfo" + ] = None + preview_image: Optional[ + "CreateMetadataResponseDataAssociatedMetadataPreviewImage" + ] = None + sensitive_media_warning: Optional[ + "CreateMetadataResponseDataAssociatedMetadataSensitiveMediaWarning" + ] = None + shared_info: Optional["CreateMetadataResponseDataAssociatedMetadataSharedInfo"] = ( + None + ) + sticker_info: Optional[ + "CreateMetadataResponseDataAssociatedMetadataStickerInfo" + ] = None + upload_source: Optional[ + "CreateMetadataResponseDataAssociatedMetadataUploadSource" + ] = None model_config = ConfigDict(populate_by_name=True) -# Models for getMediaAnalytics +class CreateMetadataResponseDataAssociatedMetadataAllowDownloadStatus(BaseModel): + """Nested model for CreateMetadataResponseDataAssociatedMetadataAllowDownloadStatus""" + allow_download: Optional[bool] = None -class GetMediaAnalyticsResponse(BaseModel): - """Response model for getMediaAnalytics""" + model_config = ConfigDict(populate_by_name=True) - data: Optional[List] = None - errors: Optional[List] = None - model_config = ConfigDict(populate_by_name=True) +class CreateMetadataResponseDataAssociatedMetadataAltText(BaseModel): + """Nested model for CreateMetadataResponseDataAssociatedMetadataAltText""" + text: Optional[str] = None -# Models for getMediaByMediaKeys + model_config = ConfigDict(populate_by_name=True) -class GetMediaByMediaKeysResponse(BaseModel): - """Response model for getMediaByMediaKeys""" +class CreateMetadataResponseDataAssociatedMetadataAudiencePolicy(BaseModel): + """Nested model for CreateMetadataResponseDataAssociatedMetadataAudiencePolicy""" - data: Optional[List] = None - errors: Optional[List] = None + creator_subscriptions: Optional[List] = None + x_subscriptions: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -# Models for getMediaByMediaKey +class CreateMetadataResponseDataAssociatedMetadataContentExpiration(BaseModel): + """Nested model for CreateMetadataResponseDataAssociatedMetadataContentExpiration""" + timestamp_sec: Optional[float] = None -class GetMediaByMediaKeyResponse(BaseModel): - """Response model for getMediaByMediaKey""" + model_config = ConfigDict(populate_by_name=True) - data: Optional["GetMediaByMediaKeyResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None + +class CreateMetadataResponseDataAssociatedMetadataDomainRestrictions(BaseModel): + """Nested model for CreateMetadataResponseDataAssociatedMetadataDomainRestrictions""" + + whitelist: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class GetMediaByMediaKeyResponseData(BaseModel): - """Nested model for GetMediaByMediaKeyResponseData""" +class CreateMetadataResponseDataAssociatedMetadataFoundMediaOrigin(BaseModel): + """Nested model for CreateMetadataResponseDataAssociatedMetadataFoundMediaOrigin""" - height: Optional[int] = None - media_key: Optional[str] = None - type: Optional[str] = None - width: Optional[int] = None + id: Optional[str] = None + provider: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -# Models for finalizeMediaUpload +class CreateMetadataResponseDataAssociatedMetadataManagementInfo(BaseModel): + """Nested model for CreateMetadataResponseDataAssociatedMetadataManagementInfo""" + + managed: Optional[bool] = None + model_config = ConfigDict(populate_by_name=True) -class FinalizeMediaUploadResponse(BaseModel): - """Response model for finalizeMediaUpload""" - data: Optional["FinalizeMediaUploadResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None +class CreateMetadataResponseDataAssociatedMetadataPreviewImage(BaseModel): + """Nested model for CreateMetadataResponseDataAssociatedMetadataPreviewImage""" + + media_key: Optional[ + "CreateMetadataResponseDataAssociatedMetadataPreviewImageMediaKey" + ] = None model_config = ConfigDict(populate_by_name=True) -class FinalizeMediaUploadResponseData(BaseModel): - """Nested model for FinalizeMediaUploadResponseData""" +class CreateMetadataResponseDataAssociatedMetadataPreviewImageMediaKey(BaseModel): + """Nested model for CreateMetadataResponseDataAssociatedMetadataPreviewImageMediaKey""" - expires_after_secs: Optional[int] = None - id: Optional[str] = None - media_key: Optional[str] = None - processing_info: Optional["FinalizeMediaUploadResponseDataProcessingInfo"] = None - size: Optional[int] = None + media: Optional[str] = None + media_category: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class FinalizeMediaUploadResponseDataProcessingInfo(BaseModel): - """Nested model for FinalizeMediaUploadResponseDataProcessingInfo""" +class CreateMetadataResponseDataAssociatedMetadataSensitiveMediaWarning(BaseModel): + """Nested model for CreateMetadataResponseDataAssociatedMetadataSensitiveMediaWarning""" - check_after_secs: Optional[int] = None - progress_percent: Optional[int] = None - state: Optional[str] = None + adult_content: Optional[bool] = None + graphic_violence: Optional[bool] = None + other: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -# Models for appendMediaUpload +class CreateMetadataResponseDataAssociatedMetadataSharedInfo(BaseModel): + """Nested model for CreateMetadataResponseDataAssociatedMetadataSharedInfo""" + + shared: Optional[bool] = None + model_config = ConfigDict(populate_by_name=True) -class AppendMediaUploadRequest(BaseModel): - """Request model for appendMediaUpload""" - media: Optional[str] = Field(default=None, description="The file to upload.") - segment_index: Optional[Any] = Field(default=None) - media: Optional[str] = Field(default=None, description="The file to upload.") - segment_index: Optional[Any] = Field(default=None) +class CreateMetadataResponseDataAssociatedMetadataStickerInfo(BaseModel): + """Nested model for CreateMetadataResponseDataAssociatedMetadataStickerInfo""" + + stickers: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class AppendMediaUploadResponse(BaseModel): - """Response model for appendMediaUpload""" +class CreateMetadataResponseDataAssociatedMetadataUploadSource(BaseModel): + """Nested model for CreateMetadataResponseDataAssociatedMetadataUploadSource""" - data: Optional["AppendMediaUploadResponseData"] = None - errors: Optional[List] = None + upload_source: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class AppendMediaUploadResponseData(BaseModel): - """Nested model for AppendMediaUploadResponseData""" +# Models for get_by_keys - expires_at: Optional[int] = None + +class GetByKeysResponse(BaseModel): + """Response model for get_by_keys""" + + data: Optional[List] = None + errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) diff --git a/xdk/python/xdk/paginator.py b/xdk/python/xdk/paginator.py index 3af61744..b5916891 100644 --- a/xdk/python/xdk/paginator.py +++ b/xdk/python/xdk/paginator.py @@ -80,9 +80,9 @@ class Cursor(Generic[ResponseType]): print(user.name) # For methods with query parameters - cursor = Cursor(client.tweets.search_posts_recent, "python", max_results=50) + cursor = Cursor(client.posts.search_posts_recent, "python", max_results=50) for page in cursor.pages(5): # page is SearchResponse type - print(f"Got {len(page.data)} tweets") + print(f"Got {len(page.data)} posts") """ @@ -161,7 +161,7 @@ def cursor( for page in users_cursor.pages(5): print(len(page.data)) # For search methods - search_cursor = cursor(client.tweets.search_posts_recent, "python", max_results=50) + search_cursor = cursor(client.posts.search_posts_recent, "python", max_results=50) for tweet in search_cursor.items(100): print(tweet.text) """ diff --git a/xdk/python/xdk/posts/__init__.py b/xdk/python/xdk/posts/__init__.py new file mode 100644 index 00000000..9dadfdbe --- /dev/null +++ b/xdk/python/xdk/posts/__init__.py @@ -0,0 +1,9 @@ +""" +posts module for the X API. + +This module provides access to the posts endpoints of the X API. +""" + +from .client import PostsClient + +__all__ = ["PostsClient"] diff --git a/xdk/python/xdk/posts/client.py b/xdk/python/xdk/posts/client.py new file mode 100644 index 00000000..932fc94c --- /dev/null +++ b/xdk/python/xdk/posts/client.py @@ -0,0 +1,1157 @@ +""" +posts client for the X API. + +This module provides a client for interacting with the posts endpoints of the X API. +""" + +from __future__ import annotations +from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING +import requests +import time + +if TYPE_CHECKING: + from ..client import Client +from .models import ( + GetInsightsHistoricalResponse, + GetCountsRecentResponse, + GetByIdsResponse, + CreateRequest, + CreateResponse, + GetInsights28hrResponse, + SearchAllResponse, + GetRepostedByResponse, + GetRepostsResponse, + GetCountsAllResponse, + SearchRecentResponse, + UnrepostPostResponse, + GetAnalyticsResponse, + RepostPostRequest, + RepostPostResponse, + LikePostRequest, + LikePostResponse, + HideReplyRequest, + HideReplyResponse, + UnlikePostResponse, + GetByIdResponse, + DeleteResponse, + GetLikingUsersResponse, + GetQuotedResponse, +) + + +class PostsClient: + """Client for posts operations""" + + + def __init__(self, client: Client): + self.client = client + + + def get_insights_historical( + self, + tweet_ids: List, + end_time: str, + start_time: str, + granularity: str, + requested_metrics: List, + ) -> GetInsightsHistoricalResponse: + """ + Get historical Post insights + Retrieves historical engagement metrics for specified Posts within a defined time range. + Args: + tweet_ids: List of PostIds for historical metrics. + Args: + end_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range. + Args: + start_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range. + Args: + granularity: granularity of metrics response. + Args: + requested_metrics: request metrics for historical request. + Returns: + GetInsightsHistoricalResponse: Response data + """ + url = self.client.base_url + "/2/insights/historical" + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + if tweet_ids is not None: + params["tweet_ids"] = ",".join(str(item) for item in tweet_ids) + if end_time is not None: + params["end_time"] = end_time + if start_time is not None: + params["start_time"] = start_time + if granularity is not None: + params["granularity"] = granularity + if requested_metrics is not None: + params["requested_metrics"] = ",".join( + str(item) for item in requested_metrics + ) + headers = {} + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.get( + url, + params=params, + headers=headers, + ) + else: + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetInsightsHistoricalResponse.model_validate(response_data) + + + def get_counts_recent( + self, + query: str, + start_time: str = None, + end_time: str = None, + since_id: Any = None, + until_id: Any = None, + next_token: Any = None, + pagination_token: Any = None, + granularity: str = None, + ) -> GetCountsRecentResponse: + """ + Get count of recent Posts + Retrieves the count of Posts from the last 7 days matching a search query. + Args: + query: One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length. + Args: + start_time: YYYY-MM-DDTHH:mm:ssZ. The oldest UTC timestamp (from most recent 7 days) from which the Posts will be provided. Timestamp is in second granularity and is inclusive (i.e. 12:00:01 includes the first second of the minute). + Args: + end_time: YYYY-MM-DDTHH:mm:ssZ. The newest, most recent UTC timestamp to which the Posts will be provided. Timestamp is in second granularity and is exclusive (i.e. 12:00:01 excludes the first second of the minute). + Args: + since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID. + Args: + until_id: Returns results with a Post ID less than (that is, older than) the specified ID. + Args: + next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. + Args: + pagination_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. + Args: + granularity: The granularity for the search counts results. + Returns: + GetCountsRecentResponse: Response data + """ + url = self.client.base_url + "/2/tweets/counts/recent" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) + params = {} + if query is not None: + params["query"] = query + if start_time is not None: + params["start_time"] = start_time + if end_time is not None: + params["end_time"] = end_time + if since_id is not None: + params["since_id"] = since_id + if until_id is not None: + params["until_id"] = until_id + if next_token is not None: + params["next_token"] = next_token + if pagination_token is not None: + params["pagination_token"] = pagination_token + if granularity is not None: + params["granularity"] = granularity + headers = {} + # Make the request + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetCountsRecentResponse.model_validate(response_data) + + + def get_by_ids( + self, + ids: List, + ) -> GetByIdsResponse: + """ + Get Posts by IDs + Retrieves details of multiple Posts by their IDs. + Args: + ids: A comma separated list of Post IDs. Up to 100 are allowed in a single request. + Returns: + GetByIdsResponse: Response data + """ + url = self.client.base_url + "/2/tweets" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + if ids is not None: + params["ids"] = ",".join(str(item) for item in ids) + headers = {} + # Make the request + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetByIdsResponse.model_validate(response_data) + + + def create( + self, + body: CreateRequest, + ) -> Dict[str, Any]: + """ + Create Post + Creates a new Post for the authenticated user. + body: Request body + Returns: + CreateResponse: Response data + """ + url = self.client.base_url + "/2/tweets" + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + headers = {} + headers["Content-Type"] = "application/json" + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.post( + url, + params=params, + headers=headers, + json=body.model_dump(exclude_none=True) if body else None, + ) + else: + response = self.client.session.post( + url, + params=params, + headers=headers, + json=body.model_dump(exclude_none=True) if body else None, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return CreateResponse.model_validate(response_data) + + + def get_insights28hr( + self, + tweet_ids: List, + granularity: str, + requested_metrics: List, + ) -> GetInsights28hrResponse: + """ + Get 28-hour Post insights + Retrieves engagement metrics for specified Posts over the last 28 hours. + Args: + tweet_ids: List of PostIds for 28hr metrics. + Args: + granularity: granularity of metrics response. + Args: + requested_metrics: request metrics for historical request. + Returns: + GetInsights28hrResponse: Response data + """ + url = self.client.base_url + "/2/insights/28hr" + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + if tweet_ids is not None: + params["tweet_ids"] = ",".join(str(item) for item in tweet_ids) + if granularity is not None: + params["granularity"] = granularity + if requested_metrics is not None: + params["requested_metrics"] = ",".join( + str(item) for item in requested_metrics + ) + headers = {} + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.get( + url, + params=params, + headers=headers, + ) + else: + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetInsights28hrResponse.model_validate(response_data) + + + def search_all( + self, + query: str, + start_time: str = None, + end_time: str = None, + since_id: Any = None, + until_id: Any = None, + max_results: int = None, + next_token: Any = None, + pagination_token: Any = None, + sort_order: str = None, + ) -> SearchAllResponse: + """ + Search all Posts + Retrieves Posts from the full archive matching a search query. + Args: + query: One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length. + Args: + start_time: YYYY-MM-DDTHH:mm:ssZ. The oldest UTC timestamp from which the Posts will be provided. Timestamp is in second granularity and is inclusive (i.e. 12:00:01 includes the first second of the minute). + Args: + end_time: YYYY-MM-DDTHH:mm:ssZ. The newest, most recent UTC timestamp to which the Posts will be provided. Timestamp is in second granularity and is exclusive (i.e. 12:00:01 excludes the first second of the minute). + Args: + since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID. + Args: + until_id: Returns results with a Post ID less than (that is, older than) the specified ID. + Args: + max_results: The maximum number of search results to be returned by a request. + Args: + next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. + Args: + pagination_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. + Args: + sort_order: This order in which to return results. + Returns: + SearchAllResponse: Response data + """ + url = self.client.base_url + "/2/tweets/search/all" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) + params = {} + if query is not None: + params["query"] = query + if start_time is not None: + params["start_time"] = start_time + if end_time is not None: + params["end_time"] = end_time + if since_id is not None: + params["since_id"] = since_id + if until_id is not None: + params["until_id"] = until_id + if max_results is not None: + params["max_results"] = max_results + if next_token is not None: + params["next_token"] = next_token + if pagination_token is not None: + params["pagination_token"] = pagination_token + if sort_order is not None: + params["sort_order"] = sort_order + headers = {} + # Make the request + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return SearchAllResponse.model_validate(response_data) + + + def get_reposted_by( + self, + id: Any, + max_results: int = None, + pagination_token: Any = None, + ) -> GetRepostedByResponse: + """ + Get Reposted by + Retrieves a list of Users who reposted a specific Post by its ID. + Args: + id: A single Post ID. + Args: + max_results: The maximum number of results. + Args: + pagination_token: This parameter is used to get the next 'page' of results. + Returns: + GetRepostedByResponse: Response data + """ + url = self.client.base_url + "/2/tweets/{id}/retweeted_by" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + if max_results is not None: + params["max_results"] = max_results + if pagination_token is not None: + params["pagination_token"] = pagination_token + url = url.replace("{id}", str(id)) + headers = {} + # Make the request + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetRepostedByResponse.model_validate(response_data) + + + def get_reposts( + self, + id: Any, + max_results: int = None, + pagination_token: Any = None, + ) -> GetRepostsResponse: + """ + Get Reposts + Retrieves a list of Posts that repost a specific Post by its ID. + Args: + id: A single Post ID. + Args: + max_results: The maximum number of results. + Args: + pagination_token: This parameter is used to get the next 'page' of results. + Returns: + GetRepostsResponse: Response data + """ + url = self.client.base_url + "/2/tweets/{id}/retweets" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + if max_results is not None: + params["max_results"] = max_results + if pagination_token is not None: + params["pagination_token"] = pagination_token + url = url.replace("{id}", str(id)) + headers = {} + # Make the request + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetRepostsResponse.model_validate(response_data) + + + def get_counts_all( + self, + query: str, + start_time: str = None, + end_time: str = None, + since_id: Any = None, + until_id: Any = None, + next_token: Any = None, + pagination_token: Any = None, + granularity: str = None, + ) -> GetCountsAllResponse: + """ + Get count of all Posts + Retrieves the count of Posts matching a search query from the full archive. + Args: + query: One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length. + Args: + start_time: YYYY-MM-DDTHH:mm:ssZ. The oldest UTC timestamp (from most recent 7 days) from which the Posts will be provided. Timestamp is in second granularity and is inclusive (i.e. 12:00:01 includes the first second of the minute). + Args: + end_time: YYYY-MM-DDTHH:mm:ssZ. The newest, most recent UTC timestamp to which the Posts will be provided. Timestamp is in second granularity and is exclusive (i.e. 12:00:01 excludes the first second of the minute). + Args: + since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID. + Args: + until_id: Returns results with a Post ID less than (that is, older than) the specified ID. + Args: + next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. + Args: + pagination_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. + Args: + granularity: The granularity for the search counts results. + Returns: + GetCountsAllResponse: Response data + """ + url = self.client.base_url + "/2/tweets/counts/all" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) + params = {} + if query is not None: + params["query"] = query + if start_time is not None: + params["start_time"] = start_time + if end_time is not None: + params["end_time"] = end_time + if since_id is not None: + params["since_id"] = since_id + if until_id is not None: + params["until_id"] = until_id + if next_token is not None: + params["next_token"] = next_token + if pagination_token is not None: + params["pagination_token"] = pagination_token + if granularity is not None: + params["granularity"] = granularity + headers = {} + # Make the request + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetCountsAllResponse.model_validate(response_data) + + + def search_recent( + self, + query: str, + start_time: str = None, + end_time: str = None, + since_id: Any = None, + until_id: Any = None, + max_results: int = None, + next_token: Any = None, + pagination_token: Any = None, + sort_order: str = None, + ) -> SearchRecentResponse: + """ + Search recent Posts + Retrieves Posts from the last 7 days matching a search query. + Args: + query: One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length. + Args: + start_time: YYYY-MM-DDTHH:mm:ssZ. The oldest UTC timestamp from which the Posts will be provided. Timestamp is in second granularity and is inclusive (i.e. 12:00:01 includes the first second of the minute). + Args: + end_time: YYYY-MM-DDTHH:mm:ssZ. The newest, most recent UTC timestamp to which the Posts will be provided. Timestamp is in second granularity and is exclusive (i.e. 12:00:01 excludes the first second of the minute). + Args: + since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID. + Args: + until_id: Returns results with a Post ID less than (that is, older than) the specified ID. + Args: + max_results: The maximum number of search results to be returned by a request. + Args: + next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. + Args: + pagination_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. + Args: + sort_order: This order in which to return results. + Returns: + SearchRecentResponse: Response data + """ + url = self.client.base_url + "/2/tweets/search/recent" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + if query is not None: + params["query"] = query + if start_time is not None: + params["start_time"] = start_time + if end_time is not None: + params["end_time"] = end_time + if since_id is not None: + params["since_id"] = since_id + if until_id is not None: + params["until_id"] = until_id + if max_results is not None: + params["max_results"] = max_results + if next_token is not None: + params["next_token"] = next_token + if pagination_token is not None: + params["pagination_token"] = pagination_token + if sort_order is not None: + params["sort_order"] = sort_order + headers = {} + # Make the request + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return SearchRecentResponse.model_validate(response_data) + + + def unrepost_post( + self, + id: Any, + source_tweet_id: Any, + ) -> UnrepostPostResponse: + """ + Unrepost Post + Causes the authenticated user to unrepost a specific Post by its ID. + Args: + id: The ID of the authenticated source User that is requesting to repost the Post. + Args: + source_tweet_id: The ID of the Post that the User is requesting to unretweet. + Returns: + UnrepostPostResponse: Response data + """ + url = self.client.base_url + "/2/users/{id}/retweets/{source_tweet_id}" + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + url = url.replace("{id}", str(id)) + url = url.replace("{source_tweet_id}", str(source_tweet_id)) + headers = {} + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.delete( + url, + params=params, + headers=headers, + ) + else: + response = self.client.session.delete( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return UnrepostPostResponse.model_validate(response_data) + + + def get_analytics( + self, + ids: List, + end_time: str, + start_time: str, + granularity: str, + ) -> GetAnalyticsResponse: + """ + Get Post analytics + Retrieves analytics data for specified Posts within a defined time range. + Args: + ids: A comma separated list of Post IDs. Up to 100 are allowed in a single request. + Args: + end_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range. + Args: + start_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range. + Args: + granularity: The granularity for the search counts results. + Returns: + GetAnalyticsResponse: Response data + """ + url = self.client.base_url + "/2/tweets/analytics" + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + if ids is not None: + params["ids"] = ",".join(str(item) for item in ids) + if end_time is not None: + params["end_time"] = end_time + if start_time is not None: + params["start_time"] = start_time + if granularity is not None: + params["granularity"] = granularity + headers = {} + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.get( + url, + params=params, + headers=headers, + ) + else: + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetAnalyticsResponse.model_validate(response_data) + + + def repost_post( + self, + id: Any, + body: Optional[RepostPostRequest] = None, + ) -> RepostPostResponse: + """ + Repost Post + Causes the authenticated user to repost a specific Post by its ID. + Args: + id: The ID of the authenticated source User that is requesting to repost the Post. + body: Request body + Returns: + RepostPostResponse: Response data + """ + url = self.client.base_url + "/2/users/{id}/retweets" + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + url = url.replace("{id}", str(id)) + headers = {} + headers["Content-Type"] = "application/json" + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.post( + url, + params=params, + headers=headers, + json=body.model_dump(exclude_none=True) if body else None, + ) + else: + response = self.client.session.post( + url, + params=params, + headers=headers, + json=body.model_dump(exclude_none=True) if body else None, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return RepostPostResponse.model_validate(response_data) + + + def like_post( + self, + id: Any, + body: Optional[LikePostRequest] = None, + ) -> LikePostResponse: + """ + Like Post + Causes the authenticated user to Like a specific Post by its ID. + Args: + id: The ID of the authenticated source User that is requesting to like the Post. + body: Request body + Returns: + LikePostResponse: Response data + """ + url = self.client.base_url + "/2/users/{id}/likes" + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + url = url.replace("{id}", str(id)) + headers = {} + headers["Content-Type"] = "application/json" + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.post( + url, + params=params, + headers=headers, + json=body.model_dump(exclude_none=True) if body else None, + ) + else: + response = self.client.session.post( + url, + params=params, + headers=headers, + json=body.model_dump(exclude_none=True) if body else None, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return LikePostResponse.model_validate(response_data) + + + def hide_reply( + self, + tweet_id: Any, + body: Optional[HideReplyRequest] = None, + ) -> HideReplyResponse: + """ + Hide reply + Hides or unhides a reply to a conversation owned by the authenticated user. + Args: + tweet_id: The ID of the reply that you want to hide or unhide. + body: Request body + Returns: + HideReplyResponse: Response data + """ + url = self.client.base_url + "/2/tweets/{tweet_id}/hidden" + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + url = url.replace("{tweet_id}", str(tweet_id)) + headers = {} + headers["Content-Type"] = "application/json" + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.put( + url, + params=params, + headers=headers, + json=body.model_dump(exclude_none=True) if body else None, + ) + else: + response = self.client.session.put( + url, + params=params, + headers=headers, + json=body.model_dump(exclude_none=True) if body else None, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return HideReplyResponse.model_validate(response_data) + + + def unlike_post( + self, + id: Any, + tweet_id: Any, + ) -> UnlikePostResponse: + """ + Unlike Post + Causes the authenticated user to Unlike a specific Post by its ID. + Args: + id: The ID of the authenticated source User that is requesting to unlike the Post. + Args: + tweet_id: The ID of the Post that the User is requesting to unlike. + Returns: + UnlikePostResponse: Response data + """ + url = self.client.base_url + "/2/users/{id}/likes/{tweet_id}" + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + url = url.replace("{id}", str(id)) + url = url.replace("{tweet_id}", str(tweet_id)) + headers = {} + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.delete( + url, + params=params, + headers=headers, + ) + else: + response = self.client.session.delete( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return UnlikePostResponse.model_validate(response_data) + + + def get_by_id( + self, + id: Any, + ) -> GetByIdResponse: + """ + Get Post by ID + Retrieves details of a specific Post by its ID. + Args: + id: A single Post ID. + Returns: + GetByIdResponse: Response data + """ + url = self.client.base_url + "/2/tweets/{id}" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + url = url.replace("{id}", str(id)) + headers = {} + # Make the request + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetByIdResponse.model_validate(response_data) + + + def delete( + self, + id: Any, + ) -> DeleteResponse: + """ + Delete Post + Deletes a specific Post by its ID, if owned by the authenticated user. + Args: + id: The ID of the Post to be deleted. + Returns: + DeleteResponse: Response data + """ + url = self.client.base_url + "/2/tweets/{id}" + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + url = url.replace("{id}", str(id)) + headers = {} + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.delete( + url, + params=params, + headers=headers, + ) + else: + response = self.client.session.delete( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return DeleteResponse.model_validate(response_data) + + + def get_liking_users( + self, + id: Any, + max_results: int = None, + pagination_token: Any = None, + ) -> GetLikingUsersResponse: + """ + Get Liking Users + Retrieves a list of Users who liked a specific Post by its ID. + Args: + id: A single Post ID. + Args: + max_results: The maximum number of results. + Args: + pagination_token: This parameter is used to get the next 'page' of results. + Returns: + GetLikingUsersResponse: Response data + """ + url = self.client.base_url + "/2/tweets/{id}/liking_users" + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + if max_results is not None: + params["max_results"] = max_results + if pagination_token is not None: + params["pagination_token"] = pagination_token + url = url.replace("{id}", str(id)) + headers = {} + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.get( + url, + params=params, + headers=headers, + ) + else: + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetLikingUsersResponse.model_validate(response_data) + + + def get_quoted( + self, + id: Any, + max_results: int = None, + pagination_token: Any = None, + exclude: List = None, + ) -> GetQuotedResponse: + """ + Get Quoted Posts + Retrieves a list of Posts that quote a specific Post by its ID. + Args: + id: A single Post ID. + Args: + max_results: The maximum number of results to be returned. + Args: + pagination_token: This parameter is used to get a specified 'page' of results. + Args: + exclude: The set of entities to exclude (e.g. 'replies' or 'retweets'). + Returns: + GetQuotedResponse: Response data + """ + url = self.client.base_url + "/2/tweets/{id}/quote_tweets" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + if max_results is not None: + params["max_results"] = max_results + if pagination_token is not None: + params["pagination_token"] = pagination_token + if exclude is not None: + params["exclude"] = ",".join(str(item) for item in exclude) + url = url.replace("{id}", str(id)) + headers = {} + # Make the request + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetQuotedResponse.model_validate(response_data) diff --git a/xdk/python/xdk/posts/models.py b/xdk/python/xdk/posts/models.py new file mode 100644 index 00000000..f78078c2 --- /dev/null +++ b/xdk/python/xdk/posts/models.py @@ -0,0 +1,763 @@ +""" +posts models for the X API. + +This module provides models for the posts endpoints of the X API. +""" + +from typing import Dict, List, Optional, Any, Union, Literal +from pydantic import BaseModel, Field, ConfigDict +from datetime import datetime + + +# Models for get_insights_historical + + +class GetInsightsHistoricalResponse(BaseModel): + """Response model for get_insights_historical""" + + data: Optional[List] = None + errors: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for get_counts_recent + + +class GetCountsRecentResponse(BaseModel): + """Response model for get_counts_recent""" + + data: Optional[List] = None + errors: Optional[List] = None + meta: Optional["GetCountsRecentResponseMeta"] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetCountsRecentResponseMeta(BaseModel): + """Nested model for GetCountsRecentResponseMeta""" + + newest_id: Optional[str] = None + next_token: Optional[str] = None + oldest_id: Optional[str] = None + total_tweet_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for get_by_ids + + +class GetByIdsResponse(BaseModel): + """Response model for get_by_ids""" + + data: Optional[List] = None + errors: Optional[List] = None + includes: Optional["GetByIdsResponseIncludes"] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByIdsResponseIncludes(BaseModel): + """Nested model for GetByIdsResponseIncludes""" + + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for create + + +class CreateRequest(BaseModel): + """Request model for create""" + + card_uri: Optional[str] = None + community_id: Optional[str] = None + direct_message_deep_link: Optional[str] = None + for_super_followers_only: Optional[bool] = None + geo: Optional["CreateRequestGeo"] = None + media: Optional["CreateRequestMedia"] = Field( + description="Media information being attached to created Tweet. This is mutually exclusive from Quote Tweet Id, Poll, and Card URI.", + default_factory=dict, + ) + nullcast: Optional[bool] = None + poll: Optional["CreateRequestPoll"] = Field( + description="Poll options for a Tweet with a poll. This is mutually exclusive from Media, Quote Tweet Id, and Card URI.", + default_factory=dict, + ) + quote_tweet_id: Optional[str] = None + reply: Optional["CreateRequestReply"] = Field( + description="Tweet information of the Tweet being replied to.", + default_factory=dict, + ) + reply_settings: Optional[str] = None + share_with_followers: Optional[bool] = None + text: Optional[str] = None + + model_config = ConfigDict(populate_by_name=True) + + +class CreateResponse(BaseModel): + """Response model for create""" + + data: Optional["CreateResponseData"] = Field(default_factory=dict) + errors: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class CreateRequestGeo(BaseModel): + """Nested model for CreateRequestGeo""" + + place_id: Optional[str] = None + + model_config = ConfigDict(populate_by_name=True) + + +class CreateRequestMedia(BaseModel): + """Nested model for CreateRequestMedia""" + + media_ids: Optional[List] = None + tagged_user_ids: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class CreateRequestPoll(BaseModel): + """Nested model for CreateRequestPoll""" + + duration_minutes: Optional[int] = None + options: Optional[List] = None + reply_settings: Optional[str] = None + + model_config = ConfigDict(populate_by_name=True) + + +class CreateRequestReply(BaseModel): + """Nested model for CreateRequestReply""" + + exclude_reply_user_ids: Optional[List] = None + in_reply_to_tweet_id: Optional[str] = None + + model_config = ConfigDict(populate_by_name=True) + + +class CreateResponseData(BaseModel): + """Nested model for CreateResponseData""" + + id: Optional[str] = None + text: Optional[str] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for get_insights28hr + + +class GetInsights28hrResponse(BaseModel): + """Response model for get_insights28hr""" + + data: Optional[List] = None + errors: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for search_all + + +class SearchAllResponse(BaseModel): + """Response model for search_all""" + + data: Optional[List] = None + errors: Optional[List] = None + includes: Optional["SearchAllResponseIncludes"] = None + meta: Optional["SearchAllResponseMeta"] = None + + model_config = ConfigDict(populate_by_name=True) + + +class SearchAllResponseIncludes(BaseModel): + """Nested model for SearchAllResponseIncludes""" + + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class SearchAllResponseMeta(BaseModel): + """Nested model for SearchAllResponseMeta""" + + newest_id: Optional[str] = None + next_token: Optional[str] = None + oldest_id: Optional[str] = None + result_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for get_reposted_by + + +class GetRepostedByResponse(BaseModel): + """Response model for get_reposted_by""" + + data: Optional[List] = None + errors: Optional[List] = None + includes: Optional["GetRepostedByResponseIncludes"] = None + meta: Optional["GetRepostedByResponseMeta"] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetRepostedByResponseIncludes(BaseModel): + """Nested model for GetRepostedByResponseIncludes""" + + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetRepostedByResponseMeta(BaseModel): + """Nested model for GetRepostedByResponseMeta""" + + next_token: Optional[str] = None + previous_token: Optional[str] = None + result_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for get_reposts + + +class GetRepostsResponse(BaseModel): + """Response model for get_reposts""" + + data: Optional[List] = None + errors: Optional[List] = None + includes: Optional["GetRepostsResponseIncludes"] = None + meta: Optional["GetRepostsResponseMeta"] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetRepostsResponseIncludes(BaseModel): + """Nested model for GetRepostsResponseIncludes""" + + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetRepostsResponseMeta(BaseModel): + """Nested model for GetRepostsResponseMeta""" + + next_token: Optional[str] = None + previous_token: Optional[str] = None + result_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for get_counts_all + + +class GetCountsAllResponse(BaseModel): + """Response model for get_counts_all""" + + data: Optional[List] = None + errors: Optional[List] = None + meta: Optional["GetCountsAllResponseMeta"] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetCountsAllResponseMeta(BaseModel): + """Nested model for GetCountsAllResponseMeta""" + + newest_id: Optional[str] = None + next_token: Optional[str] = None + oldest_id: Optional[str] = None + total_tweet_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for search_recent + + +class SearchRecentResponse(BaseModel): + """Response model for search_recent""" + + data: Optional[List] = None + errors: Optional[List] = None + includes: Optional["SearchRecentResponseIncludes"] = None + meta: Optional["SearchRecentResponseMeta"] = None + + model_config = ConfigDict(populate_by_name=True) + + +class SearchRecentResponseIncludes(BaseModel): + """Nested model for SearchRecentResponseIncludes""" + + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class SearchRecentResponseMeta(BaseModel): + """Nested model for SearchRecentResponseMeta""" + + newest_id: Optional[str] = None + next_token: Optional[str] = None + oldest_id: Optional[str] = None + result_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for unrepost_post + + +class UnrepostPostResponse(BaseModel): + """Response model for unrepost_post""" + + data: Optional["UnrepostPostResponseData"] = None + errors: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class UnrepostPostResponseData(BaseModel): + """Nested model for UnrepostPostResponseData""" + + retweeted: Optional[bool] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for get_analytics + + +class GetAnalyticsResponse(BaseModel): + """Response model for get_analytics""" + + data: Optional[List] = None + errors: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for repost_post + + +class RepostPostRequest(BaseModel): + """Request model for repost_post""" + + tweet_id: Optional[str] = None + + model_config = ConfigDict(populate_by_name=True) + + +class RepostPostResponse(BaseModel): + """Response model for repost_post""" + + data: Optional["RepostPostResponseData"] = None + errors: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class RepostPostResponseData(BaseModel): + """Nested model for RepostPostResponseData""" + + id: Optional[str] = None + retweeted: Optional[bool] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for like_post + + +class LikePostRequest(BaseModel): + """Request model for like_post""" + + tweet_id: Optional[str] = None + + model_config = ConfigDict(populate_by_name=True) + + +class LikePostResponse(BaseModel): + """Response model for like_post""" + + data: Optional["LikePostResponseData"] = None + errors: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class LikePostResponseData(BaseModel): + """Nested model for LikePostResponseData""" + + liked: Optional[bool] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for hide_reply + + +class HideReplyRequest(BaseModel): + """Request model for hide_reply""" + + hidden: Optional[bool] = None + + model_config = ConfigDict(populate_by_name=True) + + +class HideReplyResponse(BaseModel): + """Response model for hide_reply""" + + data: Optional["HideReplyResponseData"] = None + + model_config = ConfigDict(populate_by_name=True) + + +class HideReplyResponseData(BaseModel): + """Nested model for HideReplyResponseData""" + + hidden: Optional[bool] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for unlike_post + + +class UnlikePostResponse(BaseModel): + """Response model for unlike_post""" + + data: Optional["UnlikePostResponseData"] = None + errors: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class UnlikePostResponseData(BaseModel): + """Nested model for UnlikePostResponseData""" + + liked: Optional[bool] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for get_by_id + + +class GetByIdResponse(BaseModel): + """Response model for get_by_id""" + + data: Optional["GetByIdResponseData"] = None + errors: Optional[List] = None + includes: Optional["GetByIdResponseIncludes"] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByIdResponseData(BaseModel): + """Nested model for GetByIdResponseData""" + + attachments: Optional["GetByIdResponseDataAttachments"] = None + author_id: Optional[str] = None + community_id: Optional[str] = None + context_annotations: Optional[List] = None + conversation_id: Optional[str] = None + created_at: Optional[str] = None + display_text_range: Optional[List] = None + edit_controls: Optional["GetByIdResponseDataEditControls"] = None + edit_history_tweet_ids: Optional[List] = None + entities: Optional["GetByIdResponseDataEntities"] = None + geo: Optional["GetByIdResponseDataGeo"] = None + id: Optional[str] = None + in_reply_to_user_id: Optional[str] = None + lang: Optional[str] = None + non_public_metrics: Optional["GetByIdResponseDataNonPublicMetrics"] = None + note_tweet: Optional["GetByIdResponseDataNoteTweet"] = None + organic_metrics: Optional["GetByIdResponseDataOrganicMetrics"] = None + possibly_sensitive: Optional[bool] = None + promoted_metrics: Optional["GetByIdResponseDataPromotedMetrics"] = None + public_metrics: Optional["GetByIdResponseDataPublicMetrics"] = None + referenced_tweets: Optional[List] = None + reply_settings: Optional[str] = None + scopes: Optional["GetByIdResponseDataScopes"] = None + source: Optional[str] = None + text: Optional[str] = None + username: Optional[str] = None + withheld: Optional["GetByIdResponseDataWithheld"] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByIdResponseDataAttachments(BaseModel): + """Nested model for GetByIdResponseDataAttachments""" + + media_keys: Optional[List] = None + media_source_tweet_id: Optional[List] = None + poll_ids: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByIdResponseDataEditControls(BaseModel): + """Nested model for GetByIdResponseDataEditControls""" + + editable_until: Optional[str] = None + edits_remaining: Optional[int] = None + is_edit_eligible: Optional[bool] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByIdResponseDataEntities(BaseModel): + """Nested model for GetByIdResponseDataEntities""" + + annotations: Optional[List] = None + cashtags: Optional[List] = None + hashtags: Optional[List] = None + mentions: Optional[List] = None + urls: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByIdResponseDataGeo(BaseModel): + """Nested model for GetByIdResponseDataGeo""" + + coordinates: Optional["GetByIdResponseDataGeoCoordinates"] = None + place_id: Optional[str] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByIdResponseDataGeoCoordinates(BaseModel): + """Nested model for GetByIdResponseDataGeoCoordinates""" + + coordinates: Optional[List] = None + type: Optional[str] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByIdResponseDataNonPublicMetrics(BaseModel): + """Nested model for GetByIdResponseDataNonPublicMetrics""" + + impression_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByIdResponseDataNoteTweet(BaseModel): + """Nested model for GetByIdResponseDataNoteTweet""" + + entities: Optional["GetByIdResponseDataNoteTweetEntities"] = None + text: Optional[str] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByIdResponseDataNoteTweetEntities(BaseModel): + """Nested model for GetByIdResponseDataNoteTweetEntities""" + + cashtags: Optional[List] = None + hashtags: Optional[List] = None + mentions: Optional[List] = None + urls: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByIdResponseDataOrganicMetrics(BaseModel): + """Nested model for GetByIdResponseDataOrganicMetrics""" + + impression_count: Optional[int] = None + like_count: Optional[int] = None + reply_count: Optional[int] = None + retweet_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByIdResponseDataPromotedMetrics(BaseModel): + """Nested model for GetByIdResponseDataPromotedMetrics""" + + impression_count: Optional[int] = None + like_count: Optional[int] = None + reply_count: Optional[int] = None + retweet_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByIdResponseDataPublicMetrics(BaseModel): + """Nested model for GetByIdResponseDataPublicMetrics""" + + bookmark_count: Optional[int] = None + impression_count: Optional[int] = None + like_count: Optional[int] = None + quote_count: Optional[int] = None + reply_count: Optional[int] = None + retweet_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByIdResponseDataScopes(BaseModel): + """Nested model for GetByIdResponseDataScopes""" + + followers: Optional[bool] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByIdResponseDataWithheld(BaseModel): + """Nested model for GetByIdResponseDataWithheld""" + + copyright: Optional[bool] = None + country_codes: Optional[List] = None + scope: Optional[str] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByIdResponseIncludes(BaseModel): + """Nested model for GetByIdResponseIncludes""" + + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for delete + + +class DeleteResponse(BaseModel): + """Response model for delete""" + + data: Optional["DeleteResponseData"] = Field(default_factory=dict) + errors: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class DeleteResponseData(BaseModel): + """Nested model for DeleteResponseData""" + + deleted: Optional[bool] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for get_liking_users + + +class GetLikingUsersResponse(BaseModel): + """Response model for get_liking_users""" + + data: Optional[List] = None + errors: Optional[List] = None + includes: Optional["GetLikingUsersResponseIncludes"] = None + meta: Optional["GetLikingUsersResponseMeta"] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetLikingUsersResponseIncludes(BaseModel): + """Nested model for GetLikingUsersResponseIncludes""" + + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetLikingUsersResponseMeta(BaseModel): + """Nested model for GetLikingUsersResponseMeta""" + + next_token: Optional[str] = None + previous_token: Optional[str] = None + result_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for get_quoted + + +class GetQuotedResponse(BaseModel): + """Response model for get_quoted""" + + data: Optional[List] = None + errors: Optional[List] = None + includes: Optional["GetQuotedResponseIncludes"] = None + meta: Optional["GetQuotedResponseMeta"] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetQuotedResponseIncludes(BaseModel): + """Nested model for GetQuotedResponseIncludes""" + + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetQuotedResponseMeta(BaseModel): + """Nested model for GetQuotedResponseMeta""" + + next_token: Optional[str] = None + result_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) diff --git a/xdk/python/xdk/python/README.md b/xdk/python/xdk/python/README.md deleted file mode 100644 index 54ccd05f..00000000 --- a/xdk/python/xdk/python/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# XDK Python SDK - -A Python SDK for the X API. - -## Installation - -```bash -uv add xdk -``` - -Or with pip: -```bash -pip install xdk -``` - -## Usage - -```python -from xdk import Client - -# Initialize the client -client = Client( - api_key="your_api_key", - api_secret="your_api_secret", - access_token="your_access_token", - access_token_secret="your_access_token_secret" -) - -# Use the client to interact with the X API -# For example, to get tweets: -tweets = client.tweets.get_tweets(ids=["1234567890"]) - -# To search for tweets: -search_results = client.tweets.tweets_recent_search(query="python") - -# To post a tweet: -tweet = client.tweets.post_tweets(tweet_data={"text": "Hello, world!"}) -``` - -## Features - -- Full support for the X API v2 -- Simple and intuitive interface -- Comprehensive documentation -- Type hints for better IDE support - -## Documentation - -For more information, see the [documentation](https://xdk.com/docs/python). - -## License - -This project is licensed under the MIT License - see the LICENSE file for details. \ No newline at end of file diff --git a/xdk/python/xdk/python/pyproject.toml b/xdk/python/xdk/python/pyproject.toml deleted file mode 100644 index 4e791dc5..00000000 --- a/xdk/python/xdk/python/pyproject.toml +++ /dev/null @@ -1,73 +0,0 @@ -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[project] -name = "xdk" -version = "0.1.0" -description = "Python SDK for the X API" -authors = [ - {name = "XDK Team", email = "info@xdk.com"}, -] -readme = "README.md" -requires-python = ">=3.8" -classifiers = [ - "Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", -] -dependencies = [ - "requests>=2.25.0", - "requests-oauthlib>=1.3.0", - "pydantic>=2.0.0", -] - -[project.urls] -Homepage = "https://github.com/xdk/xdk-python" -Repository = "https://github.com/xdk/xdk-python" - -[project.optional-dependencies] -dev = [ - "black", - "pytest", - "pytest-cov", - "ruff", -] - -[tool.pytest.ini_options] -testpaths = ["tests"] -python_files = ["test_*.py"] -python_classes = ["Test*"] -python_functions = ["test_*"] - -[tool.black] -line-length = 88 -target-version = ['py38'] - -[tool.ruff] -target-version = "py38" -line-length = 88 -select = [ - "E", # pycodestyle errors - "W", # pycodestyle warnings - "F", # pyflakes - "I", # isort - "B", # flake8-bugbear - "C4", # flake8-comprehensions - "UP", # pyupgrade -] -ignore = [] - -[tool.ruff.per-file-ignores] -"__init__.py" = ["F401"] - -[dependency-groups] -dev = [ - "pytest>=8.3.5", -] \ No newline at end of file diff --git a/xdk/python/xdk/python/tests/__init__.py b/xdk/python/xdk/python/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/aaasubscriptions/__init__.py b/xdk/python/xdk/python/tests/aaasubscriptions/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/aaasubscriptions/test_contracts.py b/xdk/python/xdk/python/tests/aaasubscriptions/test_contracts.py deleted file mode 100644 index 6b01cbf4..00000000 --- a/xdk/python/xdk/python/tests/aaasubscriptions/test_contracts.py +++ /dev/null @@ -1,131 +0,0 @@ -""" -Auto-generated contract tests for AAASubscriptions client. - -This module contains tests that validate the request/response contracts -of the AAASubscriptions client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.aaasubscriptions.client import AaasubscriptionsClient -from xdk import Client - - -class TestAaasubscriptionsContracts: - """Test the API contracts of AaasubscriptionsClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.aaasubscriptions_client = getattr(self.client, "aaasubscriptions") - - - def test_create_account_activity_subscription_request_structure(self): - """Test create_account_activity_subscription request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["webhook_id"] = "test_value" - # Add request body if required - # Import and create proper request model instance - from xdk.aaasubscriptions.models import ( - CreateaccountactivitysubscriptionRequest, - ) - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateaccountactivitysubscriptionRequest() - # Call the method - try: - method = getattr( - self.aaasubscriptions_client, "create_account_activity_subscription" - ) - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = ( - "/2/account_activity/webhooks/{webhook_id}/subscriptions/all" - ) - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail( - f"Contract test failed for create_account_activity_subscription: {e}" - ) - - - def test_create_account_activity_subscription_required_parameters(self): - """Test that create_account_activity_subscription handles parameters correctly.""" - method = getattr( - self.aaasubscriptions_client, "create_account_activity_subscription" - ) - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_create_account_activity_subscription_response_structure(self): - """Test create_account_activity_subscription response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["webhook_id"] = "test" - # Add request body if required - # Import and create proper request model instance - from xdk.aaasubscriptions.models import ( - CreateaccountactivitysubscriptionRequest, - ) - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateaccountactivitysubscriptionRequest() - # Call method and verify response structure - method = getattr( - self.aaasubscriptions_client, "create_account_activity_subscription" - ) - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/xdk/python/tests/aaasubscriptions/test_generic.py b/xdk/python/xdk/python/tests/aaasubscriptions/test_generic.py deleted file mode 100644 index cd727b1a..00000000 --- a/xdk/python/xdk/python/tests/aaasubscriptions/test_generic.py +++ /dev/null @@ -1,125 +0,0 @@ -""" -Auto-generated generic tests for AAASubscriptions client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.aaasubscriptions.client import AaasubscriptionsClient -from xdk import Client - - -class TestAaasubscriptionsGeneric: - """Generic tests for AaasubscriptionsClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.aaasubscriptions_client = getattr(self.client, "aaasubscriptions") - - - def test_client_exists(self): - """Test that AaasubscriptionsClient class exists and is importable.""" - assert AaasubscriptionsClient is not None - assert hasattr(AaasubscriptionsClient, "__name__") - assert AaasubscriptionsClient.__name__ == "AaasubscriptionsClient" - - - def test_client_initialization(self): - """Test that AaasubscriptionsClient can be initialized properly.""" - assert self.aaasubscriptions_client is not None - assert isinstance(self.aaasubscriptions_client, AaasubscriptionsClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(AaasubscriptionsClient) - if not name.startswith("_") - and callable(getattr(AaasubscriptionsClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.aaasubscriptions_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "aaasubscriptions") - # Client should have standard Python object features - assert hasattr(self.aaasubscriptions_client, "__class__") - assert hasattr(self.aaasubscriptions_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.aaasubscriptions_client) - if not name.startswith("_") - and callable(getattr(self.aaasubscriptions_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"AaasubscriptionsClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(AaasubscriptionsClient) - if not name.startswith("_") - and callable(getattr(AaasubscriptionsClient, name)) - ] - for method_name in public_methods: - method = getattr(AaasubscriptionsClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/xdk/python/tests/aaasubscriptions/test_structure.py b/xdk/python/xdk/python/tests/aaasubscriptions/test_structure.py deleted file mode 100644 index d3a70b38..00000000 --- a/xdk/python/xdk/python/tests/aaasubscriptions/test_structure.py +++ /dev/null @@ -1,88 +0,0 @@ -""" -Auto-generated structural tests for AAASubscriptions client. - -This module contains tests that validate the structure and API surface -of the AAASubscriptions client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.aaasubscriptions.client import AaasubscriptionsClient -from xdk import Client - - -class TestAaasubscriptionsStructure: - """Test the structure of AaasubscriptionsClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.aaasubscriptions_client = getattr(self.client, "aaasubscriptions") - - - def test_create_account_activity_subscription_exists(self): - """Test that create_account_activity_subscription method exists with correct signature.""" - # Check method exists - method = getattr( - AaasubscriptionsClient, "create_account_activity_subscription", None - ) - assert ( - method is not None - ), f"Method create_account_activity_subscription does not exist on AaasubscriptionsClient" - # Check method is callable - assert callable(method), f"create_account_activity_subscription is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"create_account_activity_subscription should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "webhook_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from create_account_activity_subscription" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_create_account_activity_subscription_return_annotation(self): - """Test that create_account_activity_subscription has proper return type annotation.""" - method = getattr(AaasubscriptionsClient, "create_account_activity_subscription") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method create_account_activity_subscription should have return type annotation" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "create_account_activity_subscription", - ] - for expected_method in expected_methods: - assert hasattr( - AaasubscriptionsClient, expected_method - ), f"Expected method '{expected_method}' not found on AaasubscriptionsClient" - assert callable( - getattr(AaasubscriptionsClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/xdk/python/tests/account_activity/__init__.py b/xdk/python/xdk/python/tests/account_activity/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/account_activity/test_contracts.py b/xdk/python/xdk/python/tests/account_activity/test_contracts.py deleted file mode 100644 index 92da478f..00000000 --- a/xdk/python/xdk/python/tests/account_activity/test_contracts.py +++ /dev/null @@ -1,501 +0,0 @@ -""" -Auto-generated contract tests for Account_Activity client. - -This module contains tests that validate the request/response contracts -of the Account_Activity client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.account_activity.client import AccountActivityClient -from xdk import Client - - -class TestAccountActivityContracts: - """Test the API contracts of AccountActivityClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.account_activity_client = getattr(self.client, "account_activity") - - - def test_get_account_activity_subscription_count_request_structure(self): - """Test get_account_activity_subscription_count request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr( - self.account_activity_client, - "get_account_activity_subscription_count", - ) - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/account_activity/subscriptions/count" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail( - f"Contract test failed for get_account_activity_subscription_count: {e}" - ) - - - def test_get_account_activity_subscription_count_required_parameters(self): - """Test that get_account_activity_subscription_count handles parameters correctly.""" - method = getattr( - self.account_activity_client, "get_account_activity_subscription_count" - ) - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_get_account_activity_subscription_count_response_structure(self): - """Test get_account_activity_subscription_count response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr( - self.account_activity_client, "get_account_activity_subscription_count" - ) - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_validate_account_activity_subscription_request_structure(self): - """Test validate_account_activity_subscription request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["webhook_id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr( - self.account_activity_client, - "validate_account_activity_subscription", - ) - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = ( - "/2/account_activity/webhooks/{webhook_id}/subscriptions/all" - ) - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail( - f"Contract test failed for validate_account_activity_subscription: {e}" - ) - - - def test_validate_account_activity_subscription_required_parameters(self): - """Test that validate_account_activity_subscription handles parameters correctly.""" - method = getattr( - self.account_activity_client, "validate_account_activity_subscription" - ) - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_validate_account_activity_subscription_response_structure(self): - """Test validate_account_activity_subscription response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["webhook_id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr( - self.account_activity_client, "validate_account_activity_subscription" - ) - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_account_activity_subscriptions_request_structure(self): - """Test get_account_activity_subscriptions request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["webhook_id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr( - self.account_activity_client, "get_account_activity_subscriptions" - ) - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = ( - "/2/account_activity/webhooks/{webhook_id}/subscriptions/all/list" - ) - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail( - f"Contract test failed for get_account_activity_subscriptions: {e}" - ) - - - def test_get_account_activity_subscriptions_required_parameters(self): - """Test that get_account_activity_subscriptions handles parameters correctly.""" - method = getattr( - self.account_activity_client, "get_account_activity_subscriptions" - ) - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_account_activity_subscriptions_response_structure(self): - """Test get_account_activity_subscriptions response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["webhook_id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr( - self.account_activity_client, "get_account_activity_subscriptions" - ) - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_delete_account_activity_subscription_request_structure(self): - """Test delete_account_activity_subscription request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["webhook_id"] = "test_value" - kwargs["user_id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr( - self.account_activity_client, "delete_account_activity_subscription" - ) - result = method(**kwargs) - # Verify the request was made - mock_session.delete.assert_called_once() - # Verify request structure - call_args = mock_session.delete.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/account_activity/webhooks/{webhook_id}/subscriptions/{user_id}/all" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail( - f"Contract test failed for delete_account_activity_subscription: {e}" - ) - - - def test_delete_account_activity_subscription_required_parameters(self): - """Test that delete_account_activity_subscription handles parameters correctly.""" - method = getattr( - self.account_activity_client, "delete_account_activity_subscription" - ) - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_delete_account_activity_subscription_response_structure(self): - """Test delete_account_activity_subscription response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["webhook_id"] = "test" - kwargs["user_id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr( - self.account_activity_client, "delete_account_activity_subscription" - ) - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_create_account_activity_replay_job_request_structure(self): - """Test create_account_activity_replay_job request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["webhook_id"] = "test_value" - kwargs["from_date"] = "test_from_date" - kwargs["to_date"] = "test_to_date" - # Add request body if required - # Call the method - try: - method = getattr( - self.account_activity_client, "create_account_activity_replay_job" - ) - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = ( - "/2/account_activity/replay/webhooks/{webhook_id}/subscriptions/all" - ) - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail( - f"Contract test failed for create_account_activity_replay_job: {e}" - ) - - - def test_create_account_activity_replay_job_required_parameters(self): - """Test that create_account_activity_replay_job handles parameters correctly.""" - method = getattr( - self.account_activity_client, "create_account_activity_replay_job" - ) - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_create_account_activity_replay_job_response_structure(self): - """Test create_account_activity_replay_job response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["webhook_id"] = "test" - kwargs["from_date"] = "test_value" - kwargs["to_date"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr( - self.account_activity_client, "create_account_activity_replay_job" - ) - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/xdk/python/tests/account_activity/test_generic.py b/xdk/python/xdk/python/tests/account_activity/test_generic.py deleted file mode 100644 index 9fa5411d..00000000 --- a/xdk/python/xdk/python/tests/account_activity/test_generic.py +++ /dev/null @@ -1,125 +0,0 @@ -""" -Auto-generated generic tests for Account_Activity client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.account_activity.client import AccountActivityClient -from xdk import Client - - -class TestAccountActivityGeneric: - """Generic tests for AccountActivityClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.account_activity_client = getattr(self.client, "account_activity") - - - def test_client_exists(self): - """Test that AccountActivityClient class exists and is importable.""" - assert AccountActivityClient is not None - assert hasattr(AccountActivityClient, "__name__") - assert AccountActivityClient.__name__ == "AccountActivityClient" - - - def test_client_initialization(self): - """Test that AccountActivityClient can be initialized properly.""" - assert self.account_activity_client is not None - assert isinstance(self.account_activity_client, AccountActivityClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(AccountActivityClient) - if not name.startswith("_") - and callable(getattr(AccountActivityClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.account_activity_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "account_activity") - # Client should have standard Python object features - assert hasattr(self.account_activity_client, "__class__") - assert hasattr(self.account_activity_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.account_activity_client) - if not name.startswith("_") - and callable(getattr(self.account_activity_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"AccountActivityClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(AccountActivityClient) - if not name.startswith("_") - and callable(getattr(AccountActivityClient, name)) - ] - for method_name in public_methods: - method = getattr(AccountActivityClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/xdk/python/tests/account_activity/test_structure.py b/xdk/python/xdk/python/tests/account_activity/test_structure.py deleted file mode 100644 index 64372550..00000000 --- a/xdk/python/xdk/python/tests/account_activity/test_structure.py +++ /dev/null @@ -1,297 +0,0 @@ -""" -Auto-generated structural tests for Account_Activity client. - -This module contains tests that validate the structure and API surface -of the Account_Activity client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.account_activity.client import AccountActivityClient -from xdk import Client - - -class TestAccountActivityStructure: - """Test the structure of AccountActivityClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.account_activity_client = getattr(self.client, "account_activity") - - - def test_get_account_activity_subscription_count_exists(self): - """Test that get_account_activity_subscription_count method exists with correct signature.""" - # Check method exists - method = getattr( - AccountActivityClient, "get_account_activity_subscription_count", None - ) - assert ( - method is not None - ), f"Method get_account_activity_subscription_count does not exist on AccountActivityClient" - # Check method is callable - assert callable( - method - ), f"get_account_activity_subscription_count is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_account_activity_subscription_count should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_account_activity_subscription_count" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_account_activity_subscription_count_return_annotation(self): - """Test that get_account_activity_subscription_count has proper return type annotation.""" - method = getattr( - AccountActivityClient, "get_account_activity_subscription_count" - ) - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_account_activity_subscription_count should have return type annotation" - - - def test_validate_account_activity_subscription_exists(self): - """Test that validate_account_activity_subscription method exists with correct signature.""" - # Check method exists - method = getattr( - AccountActivityClient, "validate_account_activity_subscription", None - ) - assert ( - method is not None - ), f"Method validate_account_activity_subscription does not exist on AccountActivityClient" - # Check method is callable - assert callable( - method - ), f"validate_account_activity_subscription is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"validate_account_activity_subscription should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "webhook_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from validate_account_activity_subscription" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_validate_account_activity_subscription_return_annotation(self): - """Test that validate_account_activity_subscription has proper return type annotation.""" - method = getattr( - AccountActivityClient, "validate_account_activity_subscription" - ) - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method validate_account_activity_subscription should have return type annotation" - - - def test_get_account_activity_subscriptions_exists(self): - """Test that get_account_activity_subscriptions method exists with correct signature.""" - # Check method exists - method = getattr( - AccountActivityClient, "get_account_activity_subscriptions", None - ) - assert ( - method is not None - ), f"Method get_account_activity_subscriptions does not exist on AccountActivityClient" - # Check method is callable - assert callable(method), f"get_account_activity_subscriptions is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_account_activity_subscriptions should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "webhook_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_account_activity_subscriptions" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_account_activity_subscriptions_return_annotation(self): - """Test that get_account_activity_subscriptions has proper return type annotation.""" - method = getattr(AccountActivityClient, "get_account_activity_subscriptions") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_account_activity_subscriptions should have return type annotation" - - - def test_delete_account_activity_subscription_exists(self): - """Test that delete_account_activity_subscription method exists with correct signature.""" - # Check method exists - method = getattr( - AccountActivityClient, "delete_account_activity_subscription", None - ) - assert ( - method is not None - ), f"Method delete_account_activity_subscription does not exist on AccountActivityClient" - # Check method is callable - assert callable(method), f"delete_account_activity_subscription is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"delete_account_activity_subscription should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "webhook_id", - "user_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from delete_account_activity_subscription" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_delete_account_activity_subscription_return_annotation(self): - """Test that delete_account_activity_subscription has proper return type annotation.""" - method = getattr(AccountActivityClient, "delete_account_activity_subscription") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method delete_account_activity_subscription should have return type annotation" - - - def test_create_account_activity_replay_job_exists(self): - """Test that create_account_activity_replay_job method exists with correct signature.""" - # Check method exists - method = getattr( - AccountActivityClient, "create_account_activity_replay_job", None - ) - assert ( - method is not None - ), f"Method create_account_activity_replay_job does not exist on AccountActivityClient" - # Check method is callable - assert callable(method), f"create_account_activity_replay_job is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"create_account_activity_replay_job should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "webhook_id", - "from_date", - "to_date", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from create_account_activity_replay_job" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_create_account_activity_replay_job_return_annotation(self): - """Test that create_account_activity_replay_job has proper return type annotation.""" - method = getattr(AccountActivityClient, "create_account_activity_replay_job") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method create_account_activity_replay_job should have return type annotation" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "get_account_activity_subscription_count", - "validate_account_activity_subscription", - "get_account_activity_subscriptions", - "delete_account_activity_subscription", - "create_account_activity_replay_job", - ] - for expected_method in expected_methods: - assert hasattr( - AccountActivityClient, expected_method - ), f"Expected method '{expected_method}' not found on AccountActivityClient" - assert callable( - getattr(AccountActivityClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/xdk/python/tests/bookmarks/__init__.py b/xdk/python/xdk/python/tests/bookmarks/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/bookmarks/test_contracts.py b/xdk/python/xdk/python/tests/bookmarks/test_contracts.py deleted file mode 100644 index 21ca5083..00000000 --- a/xdk/python/xdk/python/tests/bookmarks/test_contracts.py +++ /dev/null @@ -1,465 +0,0 @@ -""" -Auto-generated contract tests for Bookmarks client. - -This module contains tests that validate the request/response contracts -of the Bookmarks client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.bookmarks.client import BookmarksClient -from xdk import Client - - -class TestBookmarksContracts: - """Test the API contracts of BookmarksClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.bookmarks_client = getattr(self.client, "bookmarks") - - - def test_delete_users_bookmark_request_structure(self): - """Test delete_users_bookmark request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - kwargs["tweet_id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.bookmarks_client, "delete_users_bookmark") - result = method(**kwargs) - # Verify the request was made - mock_session.delete.assert_called_once() - # Verify request structure - call_args = mock_session.delete.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/bookmarks/{tweet_id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for delete_users_bookmark: {e}") - - - def test_delete_users_bookmark_required_parameters(self): - """Test that delete_users_bookmark handles parameters correctly.""" - method = getattr(self.bookmarks_client, "delete_users_bookmark") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_delete_users_bookmark_response_structure(self): - """Test delete_users_bookmark response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - kwargs["tweet_id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.bookmarks_client, "delete_users_bookmark") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_users_bookmarks_request_structure(self): - """Test get_users_bookmarks request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.bookmarks_client, "get_users_bookmarks") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/bookmarks" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_users_bookmarks: {e}") - - - def test_get_users_bookmarks_required_parameters(self): - """Test that get_users_bookmarks handles parameters correctly.""" - method = getattr(self.bookmarks_client, "get_users_bookmarks") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_users_bookmarks_response_structure(self): - """Test get_users_bookmarks response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.bookmarks_client, "get_users_bookmarks") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_create_users_bookmark_request_structure(self): - """Test create_users_bookmark request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Import and create proper request model instance - from xdk.bookmarks.models import CreateusersbookmarkRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateusersbookmarkRequest() - # Call the method - try: - method = getattr(self.bookmarks_client, "create_users_bookmark") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/bookmarks" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for create_users_bookmark: {e}") - - - def test_create_users_bookmark_required_parameters(self): - """Test that create_users_bookmark handles parameters correctly.""" - method = getattr(self.bookmarks_client, "create_users_bookmark") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_create_users_bookmark_response_structure(self): - """Test create_users_bookmark response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Import and create proper request model instance - from xdk.bookmarks.models import CreateusersbookmarkRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreateusersbookmarkRequest() - # Call method and verify response structure - method = getattr(self.bookmarks_client, "create_users_bookmark") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_users_bookmark_folders_request_structure(self): - """Test get_users_bookmark_folders request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.bookmarks_client, "get_users_bookmark_folders") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/bookmarks/folders" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_users_bookmark_folders: {e}") - - - def test_get_users_bookmark_folders_required_parameters(self): - """Test that get_users_bookmark_folders handles parameters correctly.""" - method = getattr(self.bookmarks_client, "get_users_bookmark_folders") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_users_bookmark_folders_response_structure(self): - """Test get_users_bookmark_folders response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.bookmarks_client, "get_users_bookmark_folders") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_users_bookmarks_by_folder_id_request_structure(self): - """Test get_users_bookmarks_by_folder_id request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - kwargs["folder_id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr( - self.bookmarks_client, "get_users_bookmarks_by_folder_id" - ) - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/bookmarks/folders/{folder_id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail( - f"Contract test failed for get_users_bookmarks_by_folder_id: {e}" - ) - - - def test_get_users_bookmarks_by_folder_id_required_parameters(self): - """Test that get_users_bookmarks_by_folder_id handles parameters correctly.""" - method = getattr(self.bookmarks_client, "get_users_bookmarks_by_folder_id") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_users_bookmarks_by_folder_id_response_structure(self): - """Test get_users_bookmarks_by_folder_id response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - kwargs["folder_id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.bookmarks_client, "get_users_bookmarks_by_folder_id") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/xdk/python/tests/bookmarks/test_generic.py b/xdk/python/xdk/python/tests/bookmarks/test_generic.py deleted file mode 100644 index 35d5d808..00000000 --- a/xdk/python/xdk/python/tests/bookmarks/test_generic.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -Auto-generated generic tests for Bookmarks client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.bookmarks.client import BookmarksClient -from xdk import Client - - -class TestBookmarksGeneric: - """Generic tests for BookmarksClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.bookmarks_client = getattr(self.client, "bookmarks") - - - def test_client_exists(self): - """Test that BookmarksClient class exists and is importable.""" - assert BookmarksClient is not None - assert hasattr(BookmarksClient, "__name__") - assert BookmarksClient.__name__ == "BookmarksClient" - - - def test_client_initialization(self): - """Test that BookmarksClient can be initialized properly.""" - assert self.bookmarks_client is not None - assert isinstance(self.bookmarks_client, BookmarksClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(BookmarksClient) - if not name.startswith("_") and callable(getattr(BookmarksClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.bookmarks_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "bookmarks") - # Client should have standard Python object features - assert hasattr(self.bookmarks_client, "__class__") - assert hasattr(self.bookmarks_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.bookmarks_client) - if not name.startswith("_") - and callable(getattr(self.bookmarks_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"BookmarksClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(BookmarksClient) - if not name.startswith("_") and callable(getattr(BookmarksClient, name)) - ] - for method_name in public_methods: - method = getattr(BookmarksClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/xdk/python/tests/bookmarks/test_pagination.py b/xdk/python/xdk/python/tests/bookmarks/test_pagination.py deleted file mode 100644 index 83269250..00000000 --- a/xdk/python/xdk/python/tests/bookmarks/test_pagination.py +++ /dev/null @@ -1,527 +0,0 @@ -""" -Auto-generated pagination tests for Bookmarks client. - -This module contains tests that validate pagination functionality -using the Cursor class for methods that support pagination. - -Generated automatically - do not edit manually. -""" - -import pytest -from unittest.mock import Mock, patch -from xdk.bookmarks.client import BookmarksClient -from xdk import Client, Cursor, cursor, PaginationError - - -class TestBookmarksPagination: - """Test pagination functionality for BookmarksClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.bookmarks_client = getattr(self.client, "bookmarks") - - - def test_get_users_bookmarks_cursor_creation(self): - """Test that get_users_bookmarks can be used with Cursor.""" - method = getattr(self.bookmarks_client, "get_users_bookmarks") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersBookmarks should support pagination") - - - def test_get_users_bookmarks_cursor_pages(self): - """Test pagination with pages() for get_users_bookmarks.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.bookmarks_client, "get_users_bookmarks") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_bookmarks_cursor_items(self): - """Test pagination with items() for get_users_bookmarks.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.bookmarks_client, "get_users_bookmarks") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_bookmarks_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_bookmarks.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.bookmarks_client, "get_users_bookmarks") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_users_bookmark_folders_cursor_creation(self): - """Test that get_users_bookmark_folders can be used with Cursor.""" - method = getattr(self.bookmarks_client, "get_users_bookmark_folders") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersBookmarkFolders should support pagination") - - - def test_get_users_bookmark_folders_cursor_pages(self): - """Test pagination with pages() for get_users_bookmark_folders.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.bookmarks_client, "get_users_bookmark_folders") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_bookmark_folders_cursor_items(self): - """Test pagination with items() for get_users_bookmark_folders.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.bookmarks_client, "get_users_bookmark_folders") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_bookmark_folders_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_bookmark_folders.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.bookmarks_client, "get_users_bookmark_folders") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_pagination_edge_cases(self): - """Test pagination edge cases.""" - with patch.object(self.client, "session") as mock_session: - # Test empty response - empty_response = Mock() - empty_response.status_code = 200 - # Use null/None for data to handle both list and object response types - empty_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - empty_response.raise_for_status.return_value = None - mock_session.get.return_value = empty_response - # Pick first paginatable method for testing - method = getattr(self.bookmarks_client, "get_users_bookmarks") - test_cursor = cursor(method, "test_id", max_results=10) - # Should handle empty responses gracefully - pages = list(test_cursor.pages(1)) - assert len(pages) == 1, "Should get one page even if empty" - items = list(test_cursor.items(10)) - assert len(items) == 0, "Should get no items from empty response" - - - def test_non_paginatable_method_raises_error(self): - """Test that non-paginatable methods raise PaginationError.""" - # Create a mock method that doesn't support pagination - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def test_cursor_class_functionality(self): - """Test basic Cursor class functionality.""" - # Test that Cursor can be imported and instantiated - from xdk.paginator import Cursor - assert Cursor is not None - # Test cursor factory function - from xdk.paginator import cursor as cursor_factory - assert cursor_factory is not None diff --git a/xdk/python/xdk/python/tests/bookmarks/test_structure.py b/xdk/python/xdk/python/tests/bookmarks/test_structure.py deleted file mode 100644 index 79c275d0..00000000 --- a/xdk/python/xdk/python/tests/bookmarks/test_structure.py +++ /dev/null @@ -1,324 +0,0 @@ -""" -Auto-generated structural tests for Bookmarks client. - -This module contains tests that validate the structure and API surface -of the Bookmarks client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.bookmarks.client import BookmarksClient -from xdk import Client - - -class TestBookmarksStructure: - """Test the structure of BookmarksClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.bookmarks_client = getattr(self.client, "bookmarks") - - - def test_delete_users_bookmark_exists(self): - """Test that delete_users_bookmark method exists with correct signature.""" - # Check method exists - method = getattr(BookmarksClient, "delete_users_bookmark", None) - assert ( - method is not None - ), f"Method delete_users_bookmark does not exist on BookmarksClient" - # Check method is callable - assert callable(method), f"delete_users_bookmark is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"delete_users_bookmark should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - "tweet_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from delete_users_bookmark" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_delete_users_bookmark_return_annotation(self): - """Test that delete_users_bookmark has proper return type annotation.""" - method = getattr(BookmarksClient, "delete_users_bookmark") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method delete_users_bookmark should have return type annotation" - - - def test_get_users_bookmarks_exists(self): - """Test that get_users_bookmarks method exists with correct signature.""" - # Check method exists - method = getattr(BookmarksClient, "get_users_bookmarks", None) - assert ( - method is not None - ), f"Method get_users_bookmarks does not exist on BookmarksClient" - # Check method is callable - assert callable(method), f"get_users_bookmarks is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_bookmarks should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_users_bookmarks" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_users_bookmarks_return_annotation(self): - """Test that get_users_bookmarks has proper return type annotation.""" - method = getattr(BookmarksClient, "get_users_bookmarks") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_bookmarks should have return type annotation" - - - def test_get_users_bookmarks_pagination_params(self): - """Test that get_users_bookmarks has pagination parameters.""" - method = getattr(BookmarksClient, "get_users_bookmarks") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_bookmarks should have pagination parameters" - - - def test_create_users_bookmark_exists(self): - """Test that create_users_bookmark method exists with correct signature.""" - # Check method exists - method = getattr(BookmarksClient, "create_users_bookmark", None) - assert ( - method is not None - ), f"Method create_users_bookmark does not exist on BookmarksClient" - # Check method is callable - assert callable(method), f"create_users_bookmark is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"create_users_bookmark should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from create_users_bookmark" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_create_users_bookmark_return_annotation(self): - """Test that create_users_bookmark has proper return type annotation.""" - method = getattr(BookmarksClient, "create_users_bookmark") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method create_users_bookmark should have return type annotation" - - - def test_get_users_bookmark_folders_exists(self): - """Test that get_users_bookmark_folders method exists with correct signature.""" - # Check method exists - method = getattr(BookmarksClient, "get_users_bookmark_folders", None) - assert ( - method is not None - ), f"Method get_users_bookmark_folders does not exist on BookmarksClient" - # Check method is callable - assert callable(method), f"get_users_bookmark_folders is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_bookmark_folders should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_users_bookmark_folders" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_users_bookmark_folders_return_annotation(self): - """Test that get_users_bookmark_folders has proper return type annotation.""" - method = getattr(BookmarksClient, "get_users_bookmark_folders") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_bookmark_folders should have return type annotation" - - - def test_get_users_bookmark_folders_pagination_params(self): - """Test that get_users_bookmark_folders has pagination parameters.""" - method = getattr(BookmarksClient, "get_users_bookmark_folders") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_bookmark_folders should have pagination parameters" - - - def test_get_users_bookmarks_by_folder_id_exists(self): - """Test that get_users_bookmarks_by_folder_id method exists with correct signature.""" - # Check method exists - method = getattr(BookmarksClient, "get_users_bookmarks_by_folder_id", None) - assert ( - method is not None - ), f"Method get_users_bookmarks_by_folder_id does not exist on BookmarksClient" - # Check method is callable - assert callable(method), f"get_users_bookmarks_by_folder_id is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_bookmarks_by_folder_id should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - "folder_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_users_bookmarks_by_folder_id" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_users_bookmarks_by_folder_id_return_annotation(self): - """Test that get_users_bookmarks_by_folder_id has proper return type annotation.""" - method = getattr(BookmarksClient, "get_users_bookmarks_by_folder_id") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_bookmarks_by_folder_id should have return type annotation" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "delete_users_bookmark", - "get_users_bookmarks", - "create_users_bookmark", - "get_users_bookmark_folders", - "get_users_bookmarks_by_folder_id", - ] - for expected_method in expected_methods: - assert hasattr( - BookmarksClient, expected_method - ), f"Expected method '{expected_method}' not found on BookmarksClient" - assert callable( - getattr(BookmarksClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/xdk/python/tests/communities/__init__.py b/xdk/python/xdk/python/tests/communities/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/communities/test_contracts.py b/xdk/python/xdk/python/tests/communities/test_contracts.py deleted file mode 100644 index 6d1d7461..00000000 --- a/xdk/python/xdk/python/tests/communities/test_contracts.py +++ /dev/null @@ -1,194 +0,0 @@ -""" -Auto-generated contract tests for Communities client. - -This module contains tests that validate the request/response contracts -of the Communities client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.communities.client import CommunitiesClient -from xdk import Client - - -class TestCommunitiesContracts: - """Test the API contracts of CommunitiesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.communities_client = getattr(self.client, "communities") - - - def test_get_communities_by_id_request_structure(self): - """Test get_communities_by_id request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.communities_client, "get_communities_by_id") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/communities/{id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_communities_by_id: {e}") - - - def test_get_communities_by_id_required_parameters(self): - """Test that get_communities_by_id handles parameters correctly.""" - method = getattr(self.communities_client, "get_communities_by_id") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_communities_by_id_response_structure(self): - """Test get_communities_by_id response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.communities_client, "get_communities_by_id") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_search_communities_request_structure(self): - """Test search_communities request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["query"] = "test_query" - # Add request body if required - # Call the method - try: - method = getattr(self.communities_client, "search_communities") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/communities/search" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for search_communities: {e}") - - - def test_search_communities_required_parameters(self): - """Test that search_communities handles parameters correctly.""" - method = getattr(self.communities_client, "search_communities") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_search_communities_response_structure(self): - """Test search_communities response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["query"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.communities_client, "search_communities") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/xdk/python/tests/communities/test_generic.py b/xdk/python/xdk/python/tests/communities/test_generic.py deleted file mode 100644 index be58e9f8..00000000 --- a/xdk/python/xdk/python/tests/communities/test_generic.py +++ /dev/null @@ -1,124 +0,0 @@ -""" -Auto-generated generic tests for Communities client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.communities.client import CommunitiesClient -from xdk import Client - - -class TestCommunitiesGeneric: - """Generic tests for CommunitiesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.communities_client = getattr(self.client, "communities") - - - def test_client_exists(self): - """Test that CommunitiesClient class exists and is importable.""" - assert CommunitiesClient is not None - assert hasattr(CommunitiesClient, "__name__") - assert CommunitiesClient.__name__ == "CommunitiesClient" - - - def test_client_initialization(self): - """Test that CommunitiesClient can be initialized properly.""" - assert self.communities_client is not None - assert isinstance(self.communities_client, CommunitiesClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(CommunitiesClient) - if not name.startswith("_") - and callable(getattr(CommunitiesClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.communities_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "communities") - # Client should have standard Python object features - assert hasattr(self.communities_client, "__class__") - assert hasattr(self.communities_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.communities_client) - if not name.startswith("_") - and callable(getattr(self.communities_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"CommunitiesClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(CommunitiesClient) - if not name.startswith("_") and callable(getattr(CommunitiesClient, name)) - ] - for method_name in public_methods: - method = getattr(CommunitiesClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/xdk/python/tests/communities/test_pagination.py b/xdk/python/xdk/python/tests/communities/test_pagination.py deleted file mode 100644 index 17e58620..00000000 --- a/xdk/python/xdk/python/tests/communities/test_pagination.py +++ /dev/null @@ -1,382 +0,0 @@ -""" -Auto-generated pagination tests for Communities client. - -This module contains tests that validate pagination functionality -using the Cursor class for methods that support pagination. - -Generated automatically - do not edit manually. -""" - -import pytest -from unittest.mock import Mock, patch -from xdk.communities.client import CommunitiesClient -from xdk import Client, Cursor, cursor, PaginationError - - -class TestCommunitiesPagination: - """Test pagination functionality for CommunitiesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.communities_client = getattr(self.client, "communities") - - - def test_search_communities_cursor_creation(self): - """Test that search_communities can be used with Cursor.""" - method = getattr(self.communities_client, "search_communities") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_query", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method searchCommunities should support pagination") - - - def test_search_communities_cursor_pages(self): - """Test pagination with pages() for search_communities.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.communities_client, "search_communities") - test_cursor = cursor(method, "test_query", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_search_communities_cursor_items(self): - """Test pagination with items() for search_communities.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.communities_client, "search_communities") - test_cursor = cursor(method, "test_query", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_search_communities_pagination_parameters(self): - """Test that pagination parameters are handled correctly for search_communities.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.communities_client, "search_communities") - # Test with max_results parameter - test_cursor = cursor(method, "test_query", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_query", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_pagination_edge_cases(self): - """Test pagination edge cases.""" - with patch.object(self.client, "session") as mock_session: - # Test empty response - empty_response = Mock() - empty_response.status_code = 200 - # Use null/None for data to handle both list and object response types - empty_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - empty_response.raise_for_status.return_value = None - mock_session.get.return_value = empty_response - # Pick first paginatable method for testing - method = getattr(self.communities_client, "search_communities") - test_cursor = cursor(method, "test_query", max_results=10) - # Should handle empty responses gracefully - pages = list(test_cursor.pages(1)) - assert len(pages) == 1, "Should get one page even if empty" - items = list(test_cursor.items(10)) - assert len(items) == 0, "Should get no items from empty response" - - - def test_non_paginatable_method_raises_error(self): - """Test that non-paginatable methods raise PaginationError.""" - # Create a mock method that doesn't support pagination - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def test_cursor_class_functionality(self): - """Test basic Cursor class functionality.""" - # Test that Cursor can be imported and instantiated - from xdk.paginator import Cursor - assert Cursor is not None - # Test cursor factory function - from xdk.paginator import cursor as cursor_factory - assert cursor_factory is not None diff --git a/xdk/python/xdk/python/tests/communities/test_structure.py b/xdk/python/xdk/python/tests/communities/test_structure.py deleted file mode 100644 index 43a77959..00000000 --- a/xdk/python/xdk/python/tests/communities/test_structure.py +++ /dev/null @@ -1,157 +0,0 @@ -""" -Auto-generated structural tests for Communities client. - -This module contains tests that validate the structure and API surface -of the Communities client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.communities.client import CommunitiesClient -from xdk import Client - - -class TestCommunitiesStructure: - """Test the structure of CommunitiesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.communities_client = getattr(self.client, "communities") - - - def test_get_communities_by_id_exists(self): - """Test that get_communities_by_id method exists with correct signature.""" - # Check method exists - method = getattr(CommunitiesClient, "get_communities_by_id", None) - assert ( - method is not None - ), f"Method get_communities_by_id does not exist on CommunitiesClient" - # Check method is callable - assert callable(method), f"get_communities_by_id is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_communities_by_id should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_communities_by_id" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_communities_by_id_return_annotation(self): - """Test that get_communities_by_id has proper return type annotation.""" - method = getattr(CommunitiesClient, "get_communities_by_id") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_communities_by_id should have return type annotation" - - - def test_search_communities_exists(self): - """Test that search_communities method exists with correct signature.""" - # Check method exists - method = getattr(CommunitiesClient, "search_communities", None) - assert ( - method is not None - ), f"Method search_communities does not exist on CommunitiesClient" - # Check method is callable - assert callable(method), f"search_communities is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"search_communities should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "query", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from search_communities" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "next_token", - "pagination_token", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_search_communities_return_annotation(self): - """Test that search_communities has proper return type annotation.""" - method = getattr(CommunitiesClient, "search_communities") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method search_communities should have return type annotation" - - - def test_search_communities_pagination_params(self): - """Test that search_communities has pagination parameters.""" - method = getattr(CommunitiesClient, "search_communities") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method search_communities should have pagination parameters" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "get_communities_by_id", - "search_communities", - ] - for expected_method in expected_methods: - assert hasattr( - CommunitiesClient, expected_method - ), f"Expected method '{expected_method}' not found on CommunitiesClient" - assert callable( - getattr(CommunitiesClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/xdk/python/tests/community_notes/__init__.py b/xdk/python/xdk/python/tests/community_notes/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/community_notes/test_contracts.py b/xdk/python/xdk/python/tests/community_notes/test_contracts.py deleted file mode 100644 index fdf911ed..00000000 --- a/xdk/python/xdk/python/tests/community_notes/test_contracts.py +++ /dev/null @@ -1,372 +0,0 @@ -""" -Auto-generated contract tests for Community_Notes client. - -This module contains tests that validate the request/response contracts -of the Community_Notes client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.community_notes.client import CommunityNotesClient -from xdk import Client - - -class TestCommunityNotesContracts: - """Test the API contracts of CommunityNotesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.community_notes_client = getattr(self.client, "community_notes") - - - def test_create_notes_request_structure(self): - """Test create_notes request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Import and create proper request model instance - from xdk.community_notes.models import CreatenotesRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatenotesRequest() - # Call the method - try: - method = getattr(self.community_notes_client, "create_notes") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/notes" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for create_notes: {e}") - - - def test_create_notes_required_parameters(self): - """Test that create_notes handles parameters correctly.""" - method = getattr(self.community_notes_client, "create_notes") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_create_notes_response_structure(self): - """Test create_notes response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Import and create proper request model instance - from xdk.community_notes.models import CreatenotesRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatenotesRequest() - # Call method and verify response structure - method = getattr(self.community_notes_client, "create_notes") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_search_notes_written_request_structure(self): - """Test search_notes_written request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["test_mode"] = True - # Add request body if required - # Call the method - try: - method = getattr(self.community_notes_client, "search_notes_written") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/notes/search/notes_written" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for search_notes_written: {e}") - - - def test_search_notes_written_required_parameters(self): - """Test that search_notes_written handles parameters correctly.""" - method = getattr(self.community_notes_client, "search_notes_written") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_search_notes_written_response_structure(self): - """Test search_notes_written response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["test_mode"] = True - # Add request body if required - # Call method and verify response structure - method = getattr(self.community_notes_client, "search_notes_written") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_search_for_eligible_posts_request_structure(self): - """Test search_for_eligible_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["test_mode"] = True - # Add request body if required - # Call the method - try: - method = getattr( - self.community_notes_client, "search_for_eligible_posts" - ) - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/notes/search/posts_eligible_for_notes" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for search_for_eligible_posts: {e}") - - - def test_search_for_eligible_posts_required_parameters(self): - """Test that search_for_eligible_posts handles parameters correctly.""" - method = getattr(self.community_notes_client, "search_for_eligible_posts") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_search_for_eligible_posts_response_structure(self): - """Test search_for_eligible_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["test_mode"] = True - # Add request body if required - # Call method and verify response structure - method = getattr(self.community_notes_client, "search_for_eligible_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_delete_notes_request_structure(self): - """Test delete_notes request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.community_notes_client, "delete_notes") - result = method(**kwargs) - # Verify the request was made - mock_session.delete.assert_called_once() - # Verify request structure - call_args = mock_session.delete.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/notes/{id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for delete_notes: {e}") - - - def test_delete_notes_required_parameters(self): - """Test that delete_notes handles parameters correctly.""" - method = getattr(self.community_notes_client, "delete_notes") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_delete_notes_response_structure(self): - """Test delete_notes response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.community_notes_client, "delete_notes") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/xdk/python/tests/community_notes/test_generic.py b/xdk/python/xdk/python/tests/community_notes/test_generic.py deleted file mode 100644 index 6c7b8a17..00000000 --- a/xdk/python/xdk/python/tests/community_notes/test_generic.py +++ /dev/null @@ -1,125 +0,0 @@ -""" -Auto-generated generic tests for Community_Notes client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.community_notes.client import CommunityNotesClient -from xdk import Client - - -class TestCommunityNotesGeneric: - """Generic tests for CommunityNotesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.community_notes_client = getattr(self.client, "community_notes") - - - def test_client_exists(self): - """Test that CommunityNotesClient class exists and is importable.""" - assert CommunityNotesClient is not None - assert hasattr(CommunityNotesClient, "__name__") - assert CommunityNotesClient.__name__ == "CommunityNotesClient" - - - def test_client_initialization(self): - """Test that CommunityNotesClient can be initialized properly.""" - assert self.community_notes_client is not None - assert isinstance(self.community_notes_client, CommunityNotesClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(CommunityNotesClient) - if not name.startswith("_") - and callable(getattr(CommunityNotesClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.community_notes_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "community_notes") - # Client should have standard Python object features - assert hasattr(self.community_notes_client, "__class__") - assert hasattr(self.community_notes_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.community_notes_client) - if not name.startswith("_") - and callable(getattr(self.community_notes_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"CommunityNotesClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(CommunityNotesClient) - if not name.startswith("_") - and callable(getattr(CommunityNotesClient, name)) - ] - for method_name in public_methods: - method = getattr(CommunityNotesClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/xdk/python/tests/community_notes/test_pagination.py b/xdk/python/xdk/python/tests/community_notes/test_pagination.py deleted file mode 100644 index 26b9cd89..00000000 --- a/xdk/python/xdk/python/tests/community_notes/test_pagination.py +++ /dev/null @@ -1,527 +0,0 @@ -""" -Auto-generated pagination tests for Community_Notes client. - -This module contains tests that validate pagination functionality -using the Cursor class for methods that support pagination. - -Generated automatically - do not edit manually. -""" - -import pytest -from unittest.mock import Mock, patch -from xdk.community_notes.client import CommunityNotesClient -from xdk import Client, Cursor, cursor, PaginationError - - -class TestCommunityNotesPagination: - """Test pagination functionality for CommunityNotesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.community_notes_client = getattr(self.client, "community_notes") - - - def test_search_notes_written_cursor_creation(self): - """Test that search_notes_written can be used with Cursor.""" - method = getattr(self.community_notes_client, "search_notes_written") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, test_mode=True, max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method searchNotesWritten should support pagination") - - - def test_search_notes_written_cursor_pages(self): - """Test pagination with pages() for search_notes_written.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.community_notes_client, "search_notes_written") - test_cursor = cursor(method, test_mode=True, max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_search_notes_written_cursor_items(self): - """Test pagination with items() for search_notes_written.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.community_notes_client, "search_notes_written") - test_cursor = cursor(method, test_mode=True, max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_search_notes_written_pagination_parameters(self): - """Test that pagination parameters are handled correctly for search_notes_written.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.community_notes_client, "search_notes_written") - # Test with max_results parameter - test_cursor = cursor(method, test_mode=True, max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, test_mode=True, max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_search_for_eligible_posts_cursor_creation(self): - """Test that search_for_eligible_posts can be used with Cursor.""" - method = getattr(self.community_notes_client, "search_for_eligible_posts") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, test_mode=True, max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method searchForEligiblePosts should support pagination") - - - def test_search_for_eligible_posts_cursor_pages(self): - """Test pagination with pages() for search_for_eligible_posts.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.community_notes_client, "search_for_eligible_posts") - test_cursor = cursor(method, test_mode=True, max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_search_for_eligible_posts_cursor_items(self): - """Test pagination with items() for search_for_eligible_posts.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.community_notes_client, "search_for_eligible_posts") - test_cursor = cursor(method, test_mode=True, max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_search_for_eligible_posts_pagination_parameters(self): - """Test that pagination parameters are handled correctly for search_for_eligible_posts.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.community_notes_client, "search_for_eligible_posts") - # Test with max_results parameter - test_cursor = cursor(method, test_mode=True, max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, test_mode=True, max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_pagination_edge_cases(self): - """Test pagination edge cases.""" - with patch.object(self.client, "session") as mock_session: - # Test empty response - empty_response = Mock() - empty_response.status_code = 200 - # Use null/None for data to handle both list and object response types - empty_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - empty_response.raise_for_status.return_value = None - mock_session.get.return_value = empty_response - # Pick first paginatable method for testing - method = getattr(self.community_notes_client, "search_notes_written") - test_cursor = cursor(method, test_mode=True, max_results=10) - # Should handle empty responses gracefully - pages = list(test_cursor.pages(1)) - assert len(pages) == 1, "Should get one page even if empty" - items = list(test_cursor.items(10)) - assert len(items) == 0, "Should get no items from empty response" - - - def test_non_paginatable_method_raises_error(self): - """Test that non-paginatable methods raise PaginationError.""" - # Create a mock method that doesn't support pagination - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def test_cursor_class_functionality(self): - """Test basic Cursor class functionality.""" - # Test that Cursor can be imported and instantiated - from xdk.paginator import Cursor - assert Cursor is not None - # Test cursor factory function - from xdk.paginator import cursor as cursor_factory - assert cursor_factory is not None diff --git a/xdk/python/xdk/python/tests/community_notes/test_structure.py b/xdk/python/xdk/python/tests/community_notes/test_structure.py deleted file mode 100644 index 3fbd80db..00000000 --- a/xdk/python/xdk/python/tests/community_notes/test_structure.py +++ /dev/null @@ -1,268 +0,0 @@ -""" -Auto-generated structural tests for Community_Notes client. - -This module contains tests that validate the structure and API surface -of the Community_Notes client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.community_notes.client import CommunityNotesClient -from xdk import Client - - -class TestCommunityNotesStructure: - """Test the structure of CommunityNotesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.community_notes_client = getattr(self.client, "community_notes") - - - def test_create_notes_exists(self): - """Test that create_notes method exists with correct signature.""" - # Check method exists - method = getattr(CommunityNotesClient, "create_notes", None) - assert ( - method is not None - ), f"Method create_notes does not exist on CommunityNotesClient" - # Check method is callable - assert callable(method), f"create_notes is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"create_notes should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from create_notes" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_create_notes_return_annotation(self): - """Test that create_notes has proper return type annotation.""" - method = getattr(CommunityNotesClient, "create_notes") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method create_notes should have return type annotation" - - - def test_search_notes_written_exists(self): - """Test that search_notes_written method exists with correct signature.""" - # Check method exists - method = getattr(CommunityNotesClient, "search_notes_written", None) - assert ( - method is not None - ), f"Method search_notes_written does not exist on CommunityNotesClient" - # Check method is callable - assert callable(method), f"search_notes_written is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"search_notes_written should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "test_mode", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from search_notes_written" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "pagination_token", - "max_results", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_search_notes_written_return_annotation(self): - """Test that search_notes_written has proper return type annotation.""" - method = getattr(CommunityNotesClient, "search_notes_written") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method search_notes_written should have return type annotation" - - - def test_search_notes_written_pagination_params(self): - """Test that search_notes_written has pagination parameters.""" - method = getattr(CommunityNotesClient, "search_notes_written") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method search_notes_written should have pagination parameters" - - - def test_search_for_eligible_posts_exists(self): - """Test that search_for_eligible_posts method exists with correct signature.""" - # Check method exists - method = getattr(CommunityNotesClient, "search_for_eligible_posts", None) - assert ( - method is not None - ), f"Method search_for_eligible_posts does not exist on CommunityNotesClient" - # Check method is callable - assert callable(method), f"search_for_eligible_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"search_for_eligible_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "test_mode", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from search_for_eligible_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "pagination_token", - "max_results", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_search_for_eligible_posts_return_annotation(self): - """Test that search_for_eligible_posts has proper return type annotation.""" - method = getattr(CommunityNotesClient, "search_for_eligible_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method search_for_eligible_posts should have return type annotation" - - - def test_search_for_eligible_posts_pagination_params(self): - """Test that search_for_eligible_posts has pagination parameters.""" - method = getattr(CommunityNotesClient, "search_for_eligible_posts") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method search_for_eligible_posts should have pagination parameters" - - - def test_delete_notes_exists(self): - """Test that delete_notes method exists with correct signature.""" - # Check method exists - method = getattr(CommunityNotesClient, "delete_notes", None) - assert ( - method is not None - ), f"Method delete_notes does not exist on CommunityNotesClient" - # Check method is callable - assert callable(method), f"delete_notes is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"delete_notes should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from delete_notes" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_delete_notes_return_annotation(self): - """Test that delete_notes has proper return type annotation.""" - method = getattr(CommunityNotesClient, "delete_notes") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method delete_notes should have return type annotation" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "create_notes", - "search_notes_written", - "search_for_eligible_posts", - "delete_notes", - ] - for expected_method in expected_methods: - assert hasattr( - CommunityNotesClient, expected_method - ), f"Expected method '{expected_method}' not found on CommunityNotesClient" - assert callable( - getattr(CommunityNotesClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/xdk/python/tests/compliance/__init__.py b/xdk/python/xdk/python/tests/compliance/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/compliance/test_contracts.py b/xdk/python/xdk/python/tests/compliance/test_contracts.py deleted file mode 100644 index 36dff8f5..00000000 --- a/xdk/python/xdk/python/tests/compliance/test_contracts.py +++ /dev/null @@ -1,621 +0,0 @@ -""" -Auto-generated contract tests for Compliance client. - -This module contains tests that validate the request/response contracts -of the Compliance client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.compliance.client import ComplianceClient -from xdk import Client - - -class TestComplianceContracts: - """Test the API contracts of ComplianceClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.compliance_client = getattr(self.client, "compliance") - - - def test_get_compliance_jobs_request_structure(self): - """Test get_compliance_jobs request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["type"] = "test_type" - # Add request body if required - # Call the method - try: - method = getattr(self.compliance_client, "get_compliance_jobs") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/compliance/jobs" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_compliance_jobs: {e}") - - - def test_get_compliance_jobs_required_parameters(self): - """Test that get_compliance_jobs handles parameters correctly.""" - method = getattr(self.compliance_client, "get_compliance_jobs") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_compliance_jobs_response_structure(self): - """Test get_compliance_jobs response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["type"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.compliance_client, "get_compliance_jobs") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_create_compliance_jobs_request_structure(self): - """Test create_compliance_jobs request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Import and create proper request model instance - from xdk.compliance.models import CreatecompliancejobsRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatecompliancejobsRequest() - # Call the method - try: - method = getattr(self.compliance_client, "create_compliance_jobs") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/compliance/jobs" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for create_compliance_jobs: {e}") - - - def test_create_compliance_jobs_required_parameters(self): - """Test that create_compliance_jobs handles parameters correctly.""" - method = getattr(self.compliance_client, "create_compliance_jobs") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_create_compliance_jobs_response_structure(self): - """Test create_compliance_jobs response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Import and create proper request model instance - from xdk.compliance.models import CreatecompliancejobsRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatecompliancejobsRequest() - # Call method and verify response structure - method = getattr(self.compliance_client, "create_compliance_jobs") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_compliance_jobs_by_id_request_structure(self): - """Test get_compliance_jobs_by_id request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.compliance_client, "get_compliance_jobs_by_id") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/compliance/jobs/{id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_compliance_jobs_by_id: {e}") - - - def test_get_compliance_jobs_by_id_required_parameters(self): - """Test that get_compliance_jobs_by_id handles parameters correctly.""" - method = getattr(self.compliance_client, "get_compliance_jobs_by_id") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_compliance_jobs_by_id_response_structure(self): - """Test get_compliance_jobs_by_id response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.compliance_client, "get_compliance_jobs_by_id") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_likes_compliance_request_structure(self): - """Test stream_likes_compliance request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.compliance_client, "stream_likes_compliance") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/likes/compliance/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_likes_compliance: {e}") - - - def test_stream_likes_compliance_required_parameters(self): - """Test that stream_likes_compliance handles parameters correctly.""" - method = getattr(self.compliance_client, "stream_likes_compliance") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_stream_likes_compliance_response_structure(self): - """Test stream_likes_compliance response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.compliance_client, "stream_likes_compliance") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_users_compliance_request_structure(self): - """Test stream_users_compliance request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.compliance_client, "stream_users_compliance") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/compliance/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_users_compliance: {e}") - - - def test_stream_users_compliance_required_parameters(self): - """Test that stream_users_compliance handles parameters correctly.""" - method = getattr(self.compliance_client, "stream_users_compliance") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_users_compliance_response_structure(self): - """Test stream_users_compliance response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.compliance_client, "stream_users_compliance") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_labels_compliance_request_structure(self): - """Test stream_labels_compliance request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.compliance_client, "stream_labels_compliance") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/label/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_labels_compliance: {e}") - - - def test_stream_labels_compliance_required_parameters(self): - """Test that stream_labels_compliance handles parameters correctly.""" - method = getattr(self.compliance_client, "stream_labels_compliance") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_stream_labels_compliance_response_structure(self): - """Test stream_labels_compliance response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.compliance_client, "stream_labels_compliance") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_compliance_request_structure(self): - """Test stream_posts_compliance request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.compliance_client, "stream_posts_compliance") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/compliance/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_compliance: {e}") - - - def test_stream_posts_compliance_required_parameters(self): - """Test that stream_posts_compliance handles parameters correctly.""" - method = getattr(self.compliance_client, "stream_posts_compliance") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_compliance_response_structure(self): - """Test stream_posts_compliance response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.compliance_client, "stream_posts_compliance") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/xdk/python/tests/compliance/test_generic.py b/xdk/python/xdk/python/tests/compliance/test_generic.py deleted file mode 100644 index 73c26a37..00000000 --- a/xdk/python/xdk/python/tests/compliance/test_generic.py +++ /dev/null @@ -1,124 +0,0 @@ -""" -Auto-generated generic tests for Compliance client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.compliance.client import ComplianceClient -from xdk import Client - - -class TestComplianceGeneric: - """Generic tests for ComplianceClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.compliance_client = getattr(self.client, "compliance") - - - def test_client_exists(self): - """Test that ComplianceClient class exists and is importable.""" - assert ComplianceClient is not None - assert hasattr(ComplianceClient, "__name__") - assert ComplianceClient.__name__ == "ComplianceClient" - - - def test_client_initialization(self): - """Test that ComplianceClient can be initialized properly.""" - assert self.compliance_client is not None - assert isinstance(self.compliance_client, ComplianceClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(ComplianceClient) - if not name.startswith("_") - and callable(getattr(ComplianceClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.compliance_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "compliance") - # Client should have standard Python object features - assert hasattr(self.compliance_client, "__class__") - assert hasattr(self.compliance_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.compliance_client) - if not name.startswith("_") - and callable(getattr(self.compliance_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"ComplianceClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(ComplianceClient) - if not name.startswith("_") and callable(getattr(ComplianceClient, name)) - ] - for method_name in public_methods: - method = getattr(ComplianceClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/xdk/python/tests/compliance/test_structure.py b/xdk/python/xdk/python/tests/compliance/test_structure.py deleted file mode 100644 index bd98a158..00000000 --- a/xdk/python/xdk/python/tests/compliance/test_structure.py +++ /dev/null @@ -1,386 +0,0 @@ -""" -Auto-generated structural tests for Compliance client. - -This module contains tests that validate the structure and API surface -of the Compliance client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.compliance.client import ComplianceClient -from xdk import Client - - -class TestComplianceStructure: - """Test the structure of ComplianceClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.compliance_client = getattr(self.client, "compliance") - - - def test_get_compliance_jobs_exists(self): - """Test that get_compliance_jobs method exists with correct signature.""" - # Check method exists - method = getattr(ComplianceClient, "get_compliance_jobs", None) - assert ( - method is not None - ), f"Method get_compliance_jobs does not exist on ComplianceClient" - # Check method is callable - assert callable(method), f"get_compliance_jobs is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_compliance_jobs should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "type", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_compliance_jobs" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "status", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_compliance_jobs_return_annotation(self): - """Test that get_compliance_jobs has proper return type annotation.""" - method = getattr(ComplianceClient, "get_compliance_jobs") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_compliance_jobs should have return type annotation" - - - def test_create_compliance_jobs_exists(self): - """Test that create_compliance_jobs method exists with correct signature.""" - # Check method exists - method = getattr(ComplianceClient, "create_compliance_jobs", None) - assert ( - method is not None - ), f"Method create_compliance_jobs does not exist on ComplianceClient" - # Check method is callable - assert callable(method), f"create_compliance_jobs is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"create_compliance_jobs should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from create_compliance_jobs" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_create_compliance_jobs_return_annotation(self): - """Test that create_compliance_jobs has proper return type annotation.""" - method = getattr(ComplianceClient, "create_compliance_jobs") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method create_compliance_jobs should have return type annotation" - - - def test_get_compliance_jobs_by_id_exists(self): - """Test that get_compliance_jobs_by_id method exists with correct signature.""" - # Check method exists - method = getattr(ComplianceClient, "get_compliance_jobs_by_id", None) - assert ( - method is not None - ), f"Method get_compliance_jobs_by_id does not exist on ComplianceClient" - # Check method is callable - assert callable(method), f"get_compliance_jobs_by_id is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_compliance_jobs_by_id should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_compliance_jobs_by_id" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_compliance_jobs_by_id_return_annotation(self): - """Test that get_compliance_jobs_by_id has proper return type annotation.""" - method = getattr(ComplianceClient, "get_compliance_jobs_by_id") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_compliance_jobs_by_id should have return type annotation" - - - def test_stream_likes_compliance_exists(self): - """Test that stream_likes_compliance method exists with correct signature.""" - # Check method exists - method = getattr(ComplianceClient, "stream_likes_compliance", None) - assert ( - method is not None - ), f"Method stream_likes_compliance does not exist on ComplianceClient" - # Check method is callable - assert callable(method), f"stream_likes_compliance is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_likes_compliance should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_likes_compliance" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_likes_compliance_return_annotation(self): - """Test that stream_likes_compliance has proper return type annotation.""" - method = getattr(ComplianceClient, "stream_likes_compliance") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_likes_compliance should have return type annotation" - - - def test_stream_users_compliance_exists(self): - """Test that stream_users_compliance method exists with correct signature.""" - # Check method exists - method = getattr(ComplianceClient, "stream_users_compliance", None) - assert ( - method is not None - ), f"Method stream_users_compliance does not exist on ComplianceClient" - # Check method is callable - assert callable(method), f"stream_users_compliance is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_users_compliance should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_users_compliance" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_users_compliance_return_annotation(self): - """Test that stream_users_compliance has proper return type annotation.""" - method = getattr(ComplianceClient, "stream_users_compliance") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_users_compliance should have return type annotation" - - - def test_stream_labels_compliance_exists(self): - """Test that stream_labels_compliance method exists with correct signature.""" - # Check method exists - method = getattr(ComplianceClient, "stream_labels_compliance", None) - assert ( - method is not None - ), f"Method stream_labels_compliance does not exist on ComplianceClient" - # Check method is callable - assert callable(method), f"stream_labels_compliance is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_labels_compliance should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_labels_compliance" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_labels_compliance_return_annotation(self): - """Test that stream_labels_compliance has proper return type annotation.""" - method = getattr(ComplianceClient, "stream_labels_compliance") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_labels_compliance should have return type annotation" - - - def test_stream_posts_compliance_exists(self): - """Test that stream_posts_compliance method exists with correct signature.""" - # Check method exists - method = getattr(ComplianceClient, "stream_posts_compliance", None) - assert ( - method is not None - ), f"Method stream_posts_compliance does not exist on ComplianceClient" - # Check method is callable - assert callable(method), f"stream_posts_compliance is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_compliance should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_compliance" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_compliance_return_annotation(self): - """Test that stream_posts_compliance has proper return type annotation.""" - method = getattr(ComplianceClient, "stream_posts_compliance") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_compliance should have return type annotation" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "get_compliance_jobs", - "create_compliance_jobs", - "get_compliance_jobs_by_id", - "stream_likes_compliance", - "stream_users_compliance", - "stream_labels_compliance", - "stream_posts_compliance", - ] - for expected_method in expected_methods: - assert hasattr( - ComplianceClient, expected_method - ), f"Expected method '{expected_method}' not found on ComplianceClient" - assert callable( - getattr(ComplianceClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/xdk/python/tests/conftest.py b/xdk/python/xdk/python/tests/conftest.py deleted file mode 100644 index c5cfb0e3..00000000 --- a/xdk/python/xdk/python/tests/conftest.py +++ /dev/null @@ -1,21 +0,0 @@ -"""Test configuration and fixtures.""" - -import pytest -from unittest.mock import Mock -from xdk import Client - - -@pytest.fixture - - -def mock_client(): - """Provide a mock client for testing.""" - return Client(base_url="https://api.example.com") - - -@pytest.fixture - - -def mock_session(): - """Provide a mock session for HTTP requests.""" - return Mock() diff --git a/xdk/python/xdk/python/tests/connection/__init__.py b/xdk/python/xdk/python/tests/connection/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/connection/test_contracts.py b/xdk/python/xdk/python/tests/connection/test_contracts.py deleted file mode 100644 index 27fc0f9c..00000000 --- a/xdk/python/xdk/python/tests/connection/test_contracts.py +++ /dev/null @@ -1,107 +0,0 @@ -""" -Auto-generated contract tests for Connection client. - -This module contains tests that validate the request/response contracts -of the Connection client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.connection.client import ConnectionClient -from xdk import Client - - -class TestConnectionContracts: - """Test the API contracts of ConnectionClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.connection_client = getattr(self.client, "connection") - - - def test_delete_all_connections_request_structure(self): - """Test delete_all_connections request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.connection_client, "delete_all_connections") - result = method(**kwargs) - # Verify the request was made - mock_session.delete.assert_called_once() - # Verify request structure - call_args = mock_session.delete.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/connections/all" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for delete_all_connections: {e}") - - - def test_delete_all_connections_required_parameters(self): - """Test that delete_all_connections handles parameters correctly.""" - method = getattr(self.connection_client, "delete_all_connections") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_delete_all_connections_response_structure(self): - """Test delete_all_connections response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.connection_client, "delete_all_connections") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/xdk/python/tests/connection/test_generic.py b/xdk/python/xdk/python/tests/connection/test_generic.py deleted file mode 100644 index df65e008..00000000 --- a/xdk/python/xdk/python/tests/connection/test_generic.py +++ /dev/null @@ -1,124 +0,0 @@ -""" -Auto-generated generic tests for Connection client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.connection.client import ConnectionClient -from xdk import Client - - -class TestConnectionGeneric: - """Generic tests for ConnectionClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.connection_client = getattr(self.client, "connection") - - - def test_client_exists(self): - """Test that ConnectionClient class exists and is importable.""" - assert ConnectionClient is not None - assert hasattr(ConnectionClient, "__name__") - assert ConnectionClient.__name__ == "ConnectionClient" - - - def test_client_initialization(self): - """Test that ConnectionClient can be initialized properly.""" - assert self.connection_client is not None - assert isinstance(self.connection_client, ConnectionClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(ConnectionClient) - if not name.startswith("_") - and callable(getattr(ConnectionClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.connection_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "connection") - # Client should have standard Python object features - assert hasattr(self.connection_client, "__class__") - assert hasattr(self.connection_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.connection_client) - if not name.startswith("_") - and callable(getattr(self.connection_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"ConnectionClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(ConnectionClient) - if not name.startswith("_") and callable(getattr(ConnectionClient, name)) - ] - for method_name in public_methods: - method = getattr(ConnectionClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/xdk/python/tests/connection/test_structure.py b/xdk/python/xdk/python/tests/connection/test_structure.py deleted file mode 100644 index ebf7e1df..00000000 --- a/xdk/python/xdk/python/tests/connection/test_structure.py +++ /dev/null @@ -1,84 +0,0 @@ -""" -Auto-generated structural tests for Connection client. - -This module contains tests that validate the structure and API surface -of the Connection client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.connection.client import ConnectionClient -from xdk import Client - - -class TestConnectionStructure: - """Test the structure of ConnectionClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.connection_client = getattr(self.client, "connection") - - - def test_delete_all_connections_exists(self): - """Test that delete_all_connections method exists with correct signature.""" - # Check method exists - method = getattr(ConnectionClient, "delete_all_connections", None) - assert ( - method is not None - ), f"Method delete_all_connections does not exist on ConnectionClient" - # Check method is callable - assert callable(method), f"delete_all_connections is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"delete_all_connections should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from delete_all_connections" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_delete_all_connections_return_annotation(self): - """Test that delete_all_connections has proper return type annotation.""" - method = getattr(ConnectionClient, "delete_all_connections") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method delete_all_connections should have return type annotation" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "delete_all_connections", - ] - for expected_method in expected_methods: - assert hasattr( - ConnectionClient, expected_method - ), f"Expected method '{expected_method}' not found on ConnectionClient" - assert callable( - getattr(ConnectionClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/xdk/python/tests/direct_messages/__init__.py b/xdk/python/xdk/python/tests/direct_messages/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/direct_messages/test_contracts.py b/xdk/python/xdk/python/tests/direct_messages/test_contracts.py deleted file mode 100644 index 24d18a6f..00000000 --- a/xdk/python/xdk/python/tests/direct_messages/test_contracts.py +++ /dev/null @@ -1,748 +0,0 @@ -""" -Auto-generated contract tests for Direct_Messages client. - -This module contains tests that validate the request/response contracts -of the Direct_Messages client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.direct_messages.client import DirectMessagesClient -from xdk import Client - - -class TestDirectMessagesContracts: - """Test the API contracts of DirectMessagesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.direct_messages_client = getattr(self.client, "direct_messages") - - - def test_create_dm_by_conversation_id_request_structure(self): - """Test create_dm_by_conversation_id request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 201 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["dm_conversation_id"] = "test_dm_conversation_id" - # Add request body if required - # Import and create proper request model instance - from xdk.direct_messages.models import CreatedmbyconversationidRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatedmbyconversationidRequest() - # Call the method - try: - method = getattr( - self.direct_messages_client, "create_dm_by_conversation_id" - ) - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/dm_conversations/{dm_conversation_id}/messages" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail( - f"Contract test failed for create_dm_by_conversation_id: {e}" - ) - - - def test_create_dm_by_conversation_id_required_parameters(self): - """Test that create_dm_by_conversation_id handles parameters correctly.""" - method = getattr(self.direct_messages_client, "create_dm_by_conversation_id") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_create_dm_by_conversation_id_response_structure(self): - """Test create_dm_by_conversation_id response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 201 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["dm_conversation_id"] = "test_value" - # Add request body if required - # Import and create proper request model instance - from xdk.direct_messages.models import CreatedmbyconversationidRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatedmbyconversationidRequest() - # Call method and verify response structure - method = getattr( - self.direct_messages_client, "create_dm_by_conversation_id" - ) - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_create_dm_conversations_request_structure(self): - """Test create_dm_conversations request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 201 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Import and create proper request model instance - from xdk.direct_messages.models import CreatedmconversationsRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatedmconversationsRequest() - # Call the method - try: - method = getattr(self.direct_messages_client, "create_dm_conversations") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/dm_conversations" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for create_dm_conversations: {e}") - - - def test_create_dm_conversations_required_parameters(self): - """Test that create_dm_conversations handles parameters correctly.""" - method = getattr(self.direct_messages_client, "create_dm_conversations") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_create_dm_conversations_response_structure(self): - """Test create_dm_conversations response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 201 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Import and create proper request model instance - from xdk.direct_messages.models import CreatedmconversationsRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatedmconversationsRequest() - # Call method and verify response structure - method = getattr(self.direct_messages_client, "create_dm_conversations") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_dm_events_by_participant_id_request_structure(self): - """Test get_dm_events_by_participant_id request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["participant_id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr( - self.direct_messages_client, "get_dm_events_by_participant_id" - ) - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/dm_conversations/with/{participant_id}/dm_events" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail( - f"Contract test failed for get_dm_events_by_participant_id: {e}" - ) - - - def test_get_dm_events_by_participant_id_required_parameters(self): - """Test that get_dm_events_by_participant_id handles parameters correctly.""" - method = getattr(self.direct_messages_client, "get_dm_events_by_participant_id") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_dm_events_by_participant_id_response_structure(self): - """Test get_dm_events_by_participant_id response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["participant_id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr( - self.direct_messages_client, "get_dm_events_by_participant_id" - ) - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_dm_conversations_id_dm_events_request_structure(self): - """Test get_dm_conversations_id_dm_events request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr( - self.direct_messages_client, "get_dm_conversations_id_dm_events" - ) - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/dm_conversations/{id}/dm_events" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail( - f"Contract test failed for get_dm_conversations_id_dm_events: {e}" - ) - - - def test_get_dm_conversations_id_dm_events_required_parameters(self): - """Test that get_dm_conversations_id_dm_events handles parameters correctly.""" - method = getattr( - self.direct_messages_client, "get_dm_conversations_id_dm_events" - ) - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_dm_conversations_id_dm_events_response_structure(self): - """Test get_dm_conversations_id_dm_events response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr( - self.direct_messages_client, "get_dm_conversations_id_dm_events" - ) - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_dm_events_request_structure(self): - """Test get_dm_events request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.direct_messages_client, "get_dm_events") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/dm_events" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_dm_events: {e}") - - - def test_get_dm_events_required_parameters(self): - """Test that get_dm_events handles parameters correctly.""" - method = getattr(self.direct_messages_client, "get_dm_events") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_get_dm_events_response_structure(self): - """Test get_dm_events response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.direct_messages_client, "get_dm_events") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_create_dm_by_participant_id_request_structure(self): - """Test create_dm_by_participant_id request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["participant_id"] = "test_value" - # Add request body if required - # Import and create proper request model instance - from xdk.direct_messages.models import CreatedmbyparticipantidRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatedmbyparticipantidRequest() - # Call the method - try: - method = getattr( - self.direct_messages_client, "create_dm_by_participant_id" - ) - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/dm_conversations/with/{participant_id}/messages" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail( - f"Contract test failed for create_dm_by_participant_id: {e}" - ) - - - def test_create_dm_by_participant_id_required_parameters(self): - """Test that create_dm_by_participant_id handles parameters correctly.""" - method = getattr(self.direct_messages_client, "create_dm_by_participant_id") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_create_dm_by_participant_id_response_structure(self): - """Test create_dm_by_participant_id response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["participant_id"] = "test" - # Add request body if required - # Import and create proper request model instance - from xdk.direct_messages.models import CreatedmbyparticipantidRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatedmbyparticipantidRequest() - # Call method and verify response structure - method = getattr(self.direct_messages_client, "create_dm_by_participant_id") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_dm_events_by_id_request_structure(self): - """Test get_dm_events_by_id request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["event_id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.direct_messages_client, "get_dm_events_by_id") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/dm_events/{event_id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_dm_events_by_id: {e}") - - - def test_get_dm_events_by_id_required_parameters(self): - """Test that get_dm_events_by_id handles parameters correctly.""" - method = getattr(self.direct_messages_client, "get_dm_events_by_id") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_dm_events_by_id_response_structure(self): - """Test get_dm_events_by_id response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["event_id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.direct_messages_client, "get_dm_events_by_id") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_delete_dm_events_request_structure(self): - """Test delete_dm_events request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["event_id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.direct_messages_client, "delete_dm_events") - result = method(**kwargs) - # Verify the request was made - mock_session.delete.assert_called_once() - # Verify request structure - call_args = mock_session.delete.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/dm_events/{event_id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for delete_dm_events: {e}") - - - def test_delete_dm_events_required_parameters(self): - """Test that delete_dm_events handles parameters correctly.""" - method = getattr(self.direct_messages_client, "delete_dm_events") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_delete_dm_events_response_structure(self): - """Test delete_dm_events response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["event_id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.direct_messages_client, "delete_dm_events") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/xdk/python/tests/direct_messages/test_generic.py b/xdk/python/xdk/python/tests/direct_messages/test_generic.py deleted file mode 100644 index 8ac10036..00000000 --- a/xdk/python/xdk/python/tests/direct_messages/test_generic.py +++ /dev/null @@ -1,125 +0,0 @@ -""" -Auto-generated generic tests for Direct_Messages client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.direct_messages.client import DirectMessagesClient -from xdk import Client - - -class TestDirectMessagesGeneric: - """Generic tests for DirectMessagesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.direct_messages_client = getattr(self.client, "direct_messages") - - - def test_client_exists(self): - """Test that DirectMessagesClient class exists and is importable.""" - assert DirectMessagesClient is not None - assert hasattr(DirectMessagesClient, "__name__") - assert DirectMessagesClient.__name__ == "DirectMessagesClient" - - - def test_client_initialization(self): - """Test that DirectMessagesClient can be initialized properly.""" - assert self.direct_messages_client is not None - assert isinstance(self.direct_messages_client, DirectMessagesClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(DirectMessagesClient) - if not name.startswith("_") - and callable(getattr(DirectMessagesClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.direct_messages_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "direct_messages") - # Client should have standard Python object features - assert hasattr(self.direct_messages_client, "__class__") - assert hasattr(self.direct_messages_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.direct_messages_client) - if not name.startswith("_") - and callable(getattr(self.direct_messages_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"DirectMessagesClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(DirectMessagesClient) - if not name.startswith("_") - and callable(getattr(DirectMessagesClient, name)) - ] - for method_name in public_methods: - method = getattr(DirectMessagesClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/xdk/python/tests/direct_messages/test_pagination.py b/xdk/python/xdk/python/tests/direct_messages/test_pagination.py deleted file mode 100644 index 62e78d2b..00000000 --- a/xdk/python/xdk/python/tests/direct_messages/test_pagination.py +++ /dev/null @@ -1,690 +0,0 @@ -""" -Auto-generated pagination tests for Direct_Messages client. - -This module contains tests that validate pagination functionality -using the Cursor class for methods that support pagination. - -Generated automatically - do not edit manually. -""" - -import pytest -from unittest.mock import Mock, patch -from xdk.direct_messages.client import DirectMessagesClient -from xdk import Client, Cursor, cursor, PaginationError - - -class TestDirectMessagesPagination: - """Test pagination functionality for DirectMessagesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.direct_messages_client = getattr(self.client, "direct_messages") - - - def test_get_dm_events_by_participant_id_cursor_creation(self): - """Test that get_dm_events_by_participant_id can be used with Cursor.""" - method = getattr(self.direct_messages_client, "get_dm_events_by_participant_id") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getDmEventsByParticipantId should support pagination") - - - def test_get_dm_events_by_participant_id_cursor_pages(self): - """Test pagination with pages() for get_dm_events_by_participant_id.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr( - self.direct_messages_client, "get_dm_events_by_participant_id" - ) - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_dm_events_by_participant_id_cursor_items(self): - """Test pagination with items() for get_dm_events_by_participant_id.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr( - self.direct_messages_client, "get_dm_events_by_participant_id" - ) - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_dm_events_by_participant_id_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_dm_events_by_participant_id.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr( - self.direct_messages_client, "get_dm_events_by_participant_id" - ) - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_dm_conversations_id_dm_events_cursor_creation(self): - """Test that get_dm_conversations_id_dm_events can be used with Cursor.""" - method = getattr( - self.direct_messages_client, "get_dm_conversations_id_dm_events" - ) - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail( - f"Method getDmConversationsIdDmEvents should support pagination" - ) - - - def test_get_dm_conversations_id_dm_events_cursor_pages(self): - """Test pagination with pages() for get_dm_conversations_id_dm_events.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr( - self.direct_messages_client, "get_dm_conversations_id_dm_events" - ) - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_dm_conversations_id_dm_events_cursor_items(self): - """Test pagination with items() for get_dm_conversations_id_dm_events.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr( - self.direct_messages_client, "get_dm_conversations_id_dm_events" - ) - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_dm_conversations_id_dm_events_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_dm_conversations_id_dm_events.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr( - self.direct_messages_client, "get_dm_conversations_id_dm_events" - ) - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_dm_events_cursor_creation(self): - """Test that get_dm_events can be used with Cursor.""" - method = getattr(self.direct_messages_client, "get_dm_events") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getDmEvents should support pagination") - - - def test_get_dm_events_cursor_pages(self): - """Test pagination with pages() for get_dm_events.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.direct_messages_client, "get_dm_events") - test_cursor = cursor(method, max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_dm_events_cursor_items(self): - """Test pagination with items() for get_dm_events.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.direct_messages_client, "get_dm_events") - test_cursor = cursor(method, max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_dm_events_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_dm_events.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.direct_messages_client, "get_dm_events") - # Test with max_results parameter - test_cursor = cursor(method, max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_pagination_edge_cases(self): - """Test pagination edge cases.""" - with patch.object(self.client, "session") as mock_session: - # Test empty response - empty_response = Mock() - empty_response.status_code = 200 - # Use null/None for data to handle both list and object response types - empty_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - empty_response.raise_for_status.return_value = None - mock_session.get.return_value = empty_response - # Pick first paginatable method for testing - method = getattr( - self.direct_messages_client, "get_dm_events_by_participant_id" - ) - test_cursor = cursor(method, "test_id", max_results=10) - # Should handle empty responses gracefully - pages = list(test_cursor.pages(1)) - assert len(pages) == 1, "Should get one page even if empty" - items = list(test_cursor.items(10)) - assert len(items) == 0, "Should get no items from empty response" - - - def test_non_paginatable_method_raises_error(self): - """Test that non-paginatable methods raise PaginationError.""" - # Create a mock method that doesn't support pagination - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def test_cursor_class_functionality(self): - """Test basic Cursor class functionality.""" - # Test that Cursor can be imported and instantiated - from xdk.paginator import Cursor - assert Cursor is not None - # Test cursor factory function - from xdk.paginator import cursor as cursor_factory - assert cursor_factory is not None diff --git a/xdk/python/xdk/python/tests/direct_messages/test_structure.py b/xdk/python/xdk/python/tests/direct_messages/test_structure.py deleted file mode 100644 index e20769d0..00000000 --- a/xdk/python/xdk/python/tests/direct_messages/test_structure.py +++ /dev/null @@ -1,487 +0,0 @@ -""" -Auto-generated structural tests for Direct_Messages client. - -This module contains tests that validate the structure and API surface -of the Direct_Messages client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.direct_messages.client import DirectMessagesClient -from xdk import Client - - -class TestDirectMessagesStructure: - """Test the structure of DirectMessagesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.direct_messages_client = getattr(self.client, "direct_messages") - - - def test_create_dm_by_conversation_id_exists(self): - """Test that create_dm_by_conversation_id method exists with correct signature.""" - # Check method exists - method = getattr(DirectMessagesClient, "create_dm_by_conversation_id", None) - assert ( - method is not None - ), f"Method create_dm_by_conversation_id does not exist on DirectMessagesClient" - # Check method is callable - assert callable(method), f"create_dm_by_conversation_id is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"create_dm_by_conversation_id should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "dm_conversation_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from create_dm_by_conversation_id" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_create_dm_by_conversation_id_return_annotation(self): - """Test that create_dm_by_conversation_id has proper return type annotation.""" - method = getattr(DirectMessagesClient, "create_dm_by_conversation_id") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method create_dm_by_conversation_id should have return type annotation" - - - def test_create_dm_conversations_exists(self): - """Test that create_dm_conversations method exists with correct signature.""" - # Check method exists - method = getattr(DirectMessagesClient, "create_dm_conversations", None) - assert ( - method is not None - ), f"Method create_dm_conversations does not exist on DirectMessagesClient" - # Check method is callable - assert callable(method), f"create_dm_conversations is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"create_dm_conversations should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from create_dm_conversations" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_create_dm_conversations_return_annotation(self): - """Test that create_dm_conversations has proper return type annotation.""" - method = getattr(DirectMessagesClient, "create_dm_conversations") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method create_dm_conversations should have return type annotation" - - - def test_get_dm_events_by_participant_id_exists(self): - """Test that get_dm_events_by_participant_id method exists with correct signature.""" - # Check method exists - method = getattr(DirectMessagesClient, "get_dm_events_by_participant_id", None) - assert ( - method is not None - ), f"Method get_dm_events_by_participant_id does not exist on DirectMessagesClient" - # Check method is callable - assert callable(method), f"get_dm_events_by_participant_id is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_dm_events_by_participant_id should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "participant_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_dm_events_by_participant_id" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - "event_types", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_dm_events_by_participant_id_return_annotation(self): - """Test that get_dm_events_by_participant_id has proper return type annotation.""" - method = getattr(DirectMessagesClient, "get_dm_events_by_participant_id") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_dm_events_by_participant_id should have return type annotation" - - - def test_get_dm_events_by_participant_id_pagination_params(self): - """Test that get_dm_events_by_participant_id has pagination parameters.""" - method = getattr(DirectMessagesClient, "get_dm_events_by_participant_id") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_dm_events_by_participant_id should have pagination parameters" - - - def test_get_dm_conversations_id_dm_events_exists(self): - """Test that get_dm_conversations_id_dm_events method exists with correct signature.""" - # Check method exists - method = getattr( - DirectMessagesClient, "get_dm_conversations_id_dm_events", None - ) - assert ( - method is not None - ), f"Method get_dm_conversations_id_dm_events does not exist on DirectMessagesClient" - # Check method is callable - assert callable(method), f"get_dm_conversations_id_dm_events is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_dm_conversations_id_dm_events should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_dm_conversations_id_dm_events" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - "event_types", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_dm_conversations_id_dm_events_return_annotation(self): - """Test that get_dm_conversations_id_dm_events has proper return type annotation.""" - method = getattr(DirectMessagesClient, "get_dm_conversations_id_dm_events") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_dm_conversations_id_dm_events should have return type annotation" - - - def test_get_dm_conversations_id_dm_events_pagination_params(self): - """Test that get_dm_conversations_id_dm_events has pagination parameters.""" - method = getattr(DirectMessagesClient, "get_dm_conversations_id_dm_events") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_dm_conversations_id_dm_events should have pagination parameters" - - - def test_get_dm_events_exists(self): - """Test that get_dm_events method exists with correct signature.""" - # Check method exists - method = getattr(DirectMessagesClient, "get_dm_events", None) - assert ( - method is not None - ), f"Method get_dm_events does not exist on DirectMessagesClient" - # Check method is callable - assert callable(method), f"get_dm_events is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"get_dm_events should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_dm_events" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - "event_types", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_dm_events_return_annotation(self): - """Test that get_dm_events has proper return type annotation.""" - method = getattr(DirectMessagesClient, "get_dm_events") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_dm_events should have return type annotation" - - - def test_get_dm_events_pagination_params(self): - """Test that get_dm_events has pagination parameters.""" - method = getattr(DirectMessagesClient, "get_dm_events") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_dm_events should have pagination parameters" - - - def test_create_dm_by_participant_id_exists(self): - """Test that create_dm_by_participant_id method exists with correct signature.""" - # Check method exists - method = getattr(DirectMessagesClient, "create_dm_by_participant_id", None) - assert ( - method is not None - ), f"Method create_dm_by_participant_id does not exist on DirectMessagesClient" - # Check method is callable - assert callable(method), f"create_dm_by_participant_id is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"create_dm_by_participant_id should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "participant_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from create_dm_by_participant_id" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_create_dm_by_participant_id_return_annotation(self): - """Test that create_dm_by_participant_id has proper return type annotation.""" - method = getattr(DirectMessagesClient, "create_dm_by_participant_id") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method create_dm_by_participant_id should have return type annotation" - - - def test_get_dm_events_by_id_exists(self): - """Test that get_dm_events_by_id method exists with correct signature.""" - # Check method exists - method = getattr(DirectMessagesClient, "get_dm_events_by_id", None) - assert ( - method is not None - ), f"Method get_dm_events_by_id does not exist on DirectMessagesClient" - # Check method is callable - assert callable(method), f"get_dm_events_by_id is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_dm_events_by_id should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "event_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_dm_events_by_id" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_dm_events_by_id_return_annotation(self): - """Test that get_dm_events_by_id has proper return type annotation.""" - method = getattr(DirectMessagesClient, "get_dm_events_by_id") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_dm_events_by_id should have return type annotation" - - - def test_delete_dm_events_exists(self): - """Test that delete_dm_events method exists with correct signature.""" - # Check method exists - method = getattr(DirectMessagesClient, "delete_dm_events", None) - assert ( - method is not None - ), f"Method delete_dm_events does not exist on DirectMessagesClient" - # Check method is callable - assert callable(method), f"delete_dm_events is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"delete_dm_events should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "event_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from delete_dm_events" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_delete_dm_events_return_annotation(self): - """Test that delete_dm_events has proper return type annotation.""" - method = getattr(DirectMessagesClient, "delete_dm_events") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method delete_dm_events should have return type annotation" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "create_dm_by_conversation_id", - "create_dm_conversations", - "get_dm_events_by_participant_id", - "get_dm_conversations_id_dm_events", - "get_dm_events", - "create_dm_by_participant_id", - "get_dm_events_by_id", - "delete_dm_events", - ] - for expected_method in expected_methods: - assert hasattr( - DirectMessagesClient, expected_method - ), f"Expected method '{expected_method}' not found on DirectMessagesClient" - assert callable( - getattr(DirectMessagesClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/xdk/python/tests/general/__init__.py b/xdk/python/xdk/python/tests/general/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/general/test_contracts.py b/xdk/python/xdk/python/tests/general/test_contracts.py deleted file mode 100644 index 88f2bd9a..00000000 --- a/xdk/python/xdk/python/tests/general/test_contracts.py +++ /dev/null @@ -1,97 +0,0 @@ -""" -Auto-generated contract tests for General client. - -This module contains tests that validate the request/response contracts -of the General client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.general.client import GeneralClient -from xdk import Client - - -class TestGeneralContracts: - """Test the API contracts of GeneralClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.general_client = getattr(self.client, "general") - - - def test_get_open_api_spec_request_structure(self): - """Test get_open_api_spec request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.general_client, "get_open_api_spec") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/openapi.json" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_open_api_spec: {e}") - - - def test_get_open_api_spec_required_parameters(self): - """Test that get_open_api_spec handles parameters correctly.""" - method = getattr(self.general_client, "get_open_api_spec") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_get_open_api_spec_response_structure(self): - """Test get_open_api_spec response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = {} - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.general_client, "get_open_api_spec") - result = method(**kwargs) - - # Verify response object has expected attributes diff --git a/xdk/python/xdk/python/tests/general/test_generic.py b/xdk/python/xdk/python/tests/general/test_generic.py deleted file mode 100644 index c4a5f338..00000000 --- a/xdk/python/xdk/python/tests/general/test_generic.py +++ /dev/null @@ -1,122 +0,0 @@ -""" -Auto-generated generic tests for General client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.general.client import GeneralClient -from xdk import Client - - -class TestGeneralGeneric: - """Generic tests for GeneralClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.general_client = getattr(self.client, "general") - - - def test_client_exists(self): - """Test that GeneralClient class exists and is importable.""" - assert GeneralClient is not None - assert hasattr(GeneralClient, "__name__") - assert GeneralClient.__name__ == "GeneralClient" - - - def test_client_initialization(self): - """Test that GeneralClient can be initialized properly.""" - assert self.general_client is not None - assert isinstance(self.general_client, GeneralClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(GeneralClient) - if not name.startswith("_") and callable(getattr(GeneralClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.general_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "general") - # Client should have standard Python object features - assert hasattr(self.general_client, "__class__") - assert hasattr(self.general_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.general_client) - if not name.startswith("_") and callable(getattr(self.general_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"GeneralClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(GeneralClient) - if not name.startswith("_") and callable(getattr(GeneralClient, name)) - ] - for method_name in public_methods: - method = getattr(GeneralClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/xdk/python/tests/general/test_structure.py b/xdk/python/xdk/python/tests/general/test_structure.py deleted file mode 100644 index 3326d274..00000000 --- a/xdk/python/xdk/python/tests/general/test_structure.py +++ /dev/null @@ -1,84 +0,0 @@ -""" -Auto-generated structural tests for General client. - -This module contains tests that validate the structure and API surface -of the General client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.general.client import GeneralClient -from xdk import Client - - -class TestGeneralStructure: - """Test the structure of GeneralClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.general_client = getattr(self.client, "general") - - - def test_get_open_api_spec_exists(self): - """Test that get_open_api_spec method exists with correct signature.""" - # Check method exists - method = getattr(GeneralClient, "get_open_api_spec", None) - assert ( - method is not None - ), f"Method get_open_api_spec does not exist on GeneralClient" - # Check method is callable - assert callable(method), f"get_open_api_spec is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_open_api_spec should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_open_api_spec" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_open_api_spec_return_annotation(self): - """Test that get_open_api_spec has proper return type annotation.""" - method = getattr(GeneralClient, "get_open_api_spec") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_open_api_spec should have return type annotation" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "get_open_api_spec", - ] - for expected_method in expected_methods: - assert hasattr( - GeneralClient, expected_method - ), f"Expected method '{expected_method}' not found on GeneralClient" - assert callable( - getattr(GeneralClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/xdk/python/tests/likes/__init__.py b/xdk/python/xdk/python/tests/likes/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/likes/test_contracts.py b/xdk/python/xdk/python/tests/likes/test_contracts.py deleted file mode 100644 index 96b079a2..00000000 --- a/xdk/python/xdk/python/tests/likes/test_contracts.py +++ /dev/null @@ -1,194 +0,0 @@ -""" -Auto-generated contract tests for Likes client. - -This module contains tests that validate the request/response contracts -of the Likes client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.likes.client import LikesClient -from xdk import Client - - -class TestLikesContracts: - """Test the API contracts of LikesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.likes_client = getattr(self.client, "likes") - - - def test_stream_likes_firehose_request_structure(self): - """Test stream_likes_firehose request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.likes_client, "stream_likes_firehose") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/likes/firehose/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_likes_firehose: {e}") - - - def test_stream_likes_firehose_required_parameters(self): - """Test that stream_likes_firehose handles parameters correctly.""" - method = getattr(self.likes_client, "stream_likes_firehose") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_likes_firehose_response_structure(self): - """Test stream_likes_firehose response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.likes_client, "stream_likes_firehose") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_likes_sample10_request_structure(self): - """Test stream_likes_sample10 request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.likes_client, "stream_likes_sample10") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/likes/sample10/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_likes_sample10: {e}") - - - def test_stream_likes_sample10_required_parameters(self): - """Test that stream_likes_sample10 handles parameters correctly.""" - method = getattr(self.likes_client, "stream_likes_sample10") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_likes_sample10_response_structure(self): - """Test stream_likes_sample10 response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.likes_client, "stream_likes_sample10") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/xdk/python/tests/likes/test_generic.py b/xdk/python/xdk/python/tests/likes/test_generic.py deleted file mode 100644 index ef2bb285..00000000 --- a/xdk/python/xdk/python/tests/likes/test_generic.py +++ /dev/null @@ -1,122 +0,0 @@ -""" -Auto-generated generic tests for Likes client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.likes.client import LikesClient -from xdk import Client - - -class TestLikesGeneric: - """Generic tests for LikesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.likes_client = getattr(self.client, "likes") - - - def test_client_exists(self): - """Test that LikesClient class exists and is importable.""" - assert LikesClient is not None - assert hasattr(LikesClient, "__name__") - assert LikesClient.__name__ == "LikesClient" - - - def test_client_initialization(self): - """Test that LikesClient can be initialized properly.""" - assert self.likes_client is not None - assert isinstance(self.likes_client, LikesClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(LikesClient) - if not name.startswith("_") and callable(getattr(LikesClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.likes_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "likes") - # Client should have standard Python object features - assert hasattr(self.likes_client, "__class__") - assert hasattr(self.likes_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.likes_client) - if not name.startswith("_") and callable(getattr(self.likes_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"LikesClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(LikesClient) - if not name.startswith("_") and callable(getattr(LikesClient, name)) - ] - for method_name in public_methods: - method = getattr(LikesClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/xdk/python/tests/likes/test_structure.py b/xdk/python/xdk/python/tests/likes/test_structure.py deleted file mode 100644 index 0307474b..00000000 --- a/xdk/python/xdk/python/tests/likes/test_structure.py +++ /dev/null @@ -1,142 +0,0 @@ -""" -Auto-generated structural tests for Likes client. - -This module contains tests that validate the structure and API surface -of the Likes client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.likes.client import LikesClient -from xdk import Client - - -class TestLikesStructure: - """Test the structure of LikesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.likes_client = getattr(self.client, "likes") - - - def test_stream_likes_firehose_exists(self): - """Test that stream_likes_firehose method exists with correct signature.""" - # Check method exists - method = getattr(LikesClient, "stream_likes_firehose", None) - assert ( - method is not None - ), f"Method stream_likes_firehose does not exist on LikesClient" - # Check method is callable - assert callable(method), f"stream_likes_firehose is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_likes_firehose should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_likes_firehose" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_likes_firehose_return_annotation(self): - """Test that stream_likes_firehose has proper return type annotation.""" - method = getattr(LikesClient, "stream_likes_firehose") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_likes_firehose should have return type annotation" - - - def test_stream_likes_sample10_exists(self): - """Test that stream_likes_sample10 method exists with correct signature.""" - # Check method exists - method = getattr(LikesClient, "stream_likes_sample10", None) - assert ( - method is not None - ), f"Method stream_likes_sample10 does not exist on LikesClient" - # Check method is callable - assert callable(method), f"stream_likes_sample10 is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_likes_sample10 should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_likes_sample10" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_likes_sample10_return_annotation(self): - """Test that stream_likes_sample10 has proper return type annotation.""" - method = getattr(LikesClient, "stream_likes_sample10") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_likes_sample10 should have return type annotation" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "stream_likes_firehose", - "stream_likes_sample10", - ] - for expected_method in expected_methods: - assert hasattr( - LikesClient, expected_method - ), f"Expected method '{expected_method}' not found on LikesClient" - assert callable( - getattr(LikesClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/xdk/python/tests/lists/__init__.py b/xdk/python/xdk/python/tests/lists/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/lists/test_contracts.py b/xdk/python/xdk/python/tests/lists/test_contracts.py deleted file mode 100644 index c590241b..00000000 --- a/xdk/python/xdk/python/tests/lists/test_contracts.py +++ /dev/null @@ -1,1260 +0,0 @@ -""" -Auto-generated contract tests for Lists client. - -This module contains tests that validate the request/response contracts -of the Lists client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.lists.client import ListsClient -from xdk import Client - - -class TestListsContracts: - """Test the API contracts of ListsClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.lists_client = getattr(self.client, "lists") - - - def test_unfollow_list_request_structure(self): - """Test unfollow_list request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - kwargs["list_id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.lists_client, "unfollow_list") - result = method(**kwargs) - # Verify the request was made - mock_session.delete.assert_called_once() - # Verify request structure - call_args = mock_session.delete.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/followed_lists/{list_id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for unfollow_list: {e}") - - - def test_unfollow_list_required_parameters(self): - """Test that unfollow_list handles parameters correctly.""" - method = getattr(self.lists_client, "unfollow_list") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_unfollow_list_response_structure(self): - """Test unfollow_list response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - kwargs["list_id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.lists_client, "unfollow_list") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_unpin_list_request_structure(self): - """Test unpin_list request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - kwargs["list_id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.lists_client, "unpin_list") - result = method(**kwargs) - # Verify the request was made - mock_session.delete.assert_called_once() - # Verify request structure - call_args = mock_session.delete.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/pinned_lists/{list_id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for unpin_list: {e}") - - - def test_unpin_list_required_parameters(self): - """Test that unpin_list handles parameters correctly.""" - method = getattr(self.lists_client, "unpin_list") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_unpin_list_response_structure(self): - """Test unpin_list response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - kwargs["list_id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.lists_client, "unpin_list") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_add_lists_member_request_structure(self): - """Test add_lists_member request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Import and create proper request model instance - from xdk.lists.models import AddlistsmemberRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = AddlistsmemberRequest() - # Call the method - try: - method = getattr(self.lists_client, "add_lists_member") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/lists/{id}/members" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for add_lists_member: {e}") - - - def test_add_lists_member_required_parameters(self): - """Test that add_lists_member handles parameters correctly.""" - method = getattr(self.lists_client, "add_lists_member") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_add_lists_member_response_structure(self): - """Test add_lists_member response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Import and create proper request model instance - from xdk.lists.models import AddlistsmemberRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = AddlistsmemberRequest() - # Call method and verify response structure - method = getattr(self.lists_client, "add_lists_member") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_remove_lists_member_by_user_id_request_structure(self): - """Test remove_lists_member_by_user_id request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - kwargs["user_id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.lists_client, "remove_lists_member_by_user_id") - result = method(**kwargs) - # Verify the request was made - mock_session.delete.assert_called_once() - # Verify request structure - call_args = mock_session.delete.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/lists/{id}/members/{user_id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail( - f"Contract test failed for remove_lists_member_by_user_id: {e}" - ) - - - def test_remove_lists_member_by_user_id_required_parameters(self): - """Test that remove_lists_member_by_user_id handles parameters correctly.""" - method = getattr(self.lists_client, "remove_lists_member_by_user_id") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_remove_lists_member_by_user_id_response_structure(self): - """Test remove_lists_member_by_user_id response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - kwargs["user_id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.lists_client, "remove_lists_member_by_user_id") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_users_followed_lists_request_structure(self): - """Test get_users_followed_lists request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.lists_client, "get_users_followed_lists") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/followed_lists" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_users_followed_lists: {e}") - - - def test_get_users_followed_lists_required_parameters(self): - """Test that get_users_followed_lists handles parameters correctly.""" - method = getattr(self.lists_client, "get_users_followed_lists") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_users_followed_lists_response_structure(self): - """Test get_users_followed_lists response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.lists_client, "get_users_followed_lists") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_follow_list_request_structure(self): - """Test follow_list request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Import and create proper request model instance - from xdk.lists.models import FollowlistRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = FollowlistRequest() - # Call the method - try: - method = getattr(self.lists_client, "follow_list") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/followed_lists" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for follow_list: {e}") - - - def test_follow_list_required_parameters(self): - """Test that follow_list handles parameters correctly.""" - method = getattr(self.lists_client, "follow_list") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_follow_list_response_structure(self): - """Test follow_list response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Import and create proper request model instance - from xdk.lists.models import FollowlistRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = FollowlistRequest() - # Call method and verify response structure - method = getattr(self.lists_client, "follow_list") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_create_lists_request_structure(self): - """Test create_lists request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Import and create proper request model instance - from xdk.lists.models import CreatelistsRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatelistsRequest() - # Call the method - try: - method = getattr(self.lists_client, "create_lists") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/lists" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for create_lists: {e}") - - - def test_create_lists_required_parameters(self): - """Test that create_lists handles parameters correctly.""" - method = getattr(self.lists_client, "create_lists") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_create_lists_response_structure(self): - """Test create_lists response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Import and create proper request model instance - from xdk.lists.models import CreatelistsRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatelistsRequest() - # Call method and verify response structure - method = getattr(self.lists_client, "create_lists") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_lists_by_id_request_structure(self): - """Test get_lists_by_id request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.lists_client, "get_lists_by_id") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/lists/{id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_lists_by_id: {e}") - - - def test_get_lists_by_id_required_parameters(self): - """Test that get_lists_by_id handles parameters correctly.""" - method = getattr(self.lists_client, "get_lists_by_id") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_lists_by_id_response_structure(self): - """Test get_lists_by_id response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.lists_client, "get_lists_by_id") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_update_lists_request_structure(self): - """Test update_lists request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.put.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Import and create proper request model instance - from xdk.lists.models import UpdatelistsRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = UpdatelistsRequest() - # Call the method - try: - method = getattr(self.lists_client, "update_lists") - result = method(**kwargs) - # Verify the request was made - mock_session.put.assert_called_once() - # Verify request structure - call_args = mock_session.put.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/lists/{id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for update_lists: {e}") - - - def test_update_lists_required_parameters(self): - """Test that update_lists handles parameters correctly.""" - method = getattr(self.lists_client, "update_lists") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.put.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_update_lists_response_structure(self): - """Test update_lists response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.put.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Import and create proper request model instance - from xdk.lists.models import UpdatelistsRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = UpdatelistsRequest() - # Call method and verify response structure - method = getattr(self.lists_client, "update_lists") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_delete_lists_request_structure(self): - """Test delete_lists request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.lists_client, "delete_lists") - result = method(**kwargs) - # Verify the request was made - mock_session.delete.assert_called_once() - # Verify request structure - call_args = mock_session.delete.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/lists/{id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for delete_lists: {e}") - - - def test_delete_lists_required_parameters(self): - """Test that delete_lists handles parameters correctly.""" - method = getattr(self.lists_client, "delete_lists") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_delete_lists_response_structure(self): - """Test delete_lists response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.lists_client, "delete_lists") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_users_pinned_lists_request_structure(self): - """Test get_users_pinned_lists request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.lists_client, "get_users_pinned_lists") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/pinned_lists" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_users_pinned_lists: {e}") - - - def test_get_users_pinned_lists_required_parameters(self): - """Test that get_users_pinned_lists handles parameters correctly.""" - method = getattr(self.lists_client, "get_users_pinned_lists") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_users_pinned_lists_response_structure(self): - """Test get_users_pinned_lists response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.lists_client, "get_users_pinned_lists") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_pin_list_request_structure(self): - """Test pin_list request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Import and create proper request model instance - from xdk.lists.models import PinlistRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = PinlistRequest() - # Call the method - try: - method = getattr(self.lists_client, "pin_list") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/pinned_lists" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for pin_list: {e}") - - - def test_pin_list_required_parameters(self): - """Test that pin_list handles parameters correctly.""" - method = getattr(self.lists_client, "pin_list") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_pin_list_response_structure(self): - """Test pin_list response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Import and create proper request model instance - from xdk.lists.models import PinlistRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = PinlistRequest() - # Call method and verify response structure - method = getattr(self.lists_client, "pin_list") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_users_list_memberships_request_structure(self): - """Test get_users_list_memberships request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.lists_client, "get_users_list_memberships") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/list_memberships" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_users_list_memberships: {e}") - - - def test_get_users_list_memberships_required_parameters(self): - """Test that get_users_list_memberships handles parameters correctly.""" - method = getattr(self.lists_client, "get_users_list_memberships") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_users_list_memberships_response_structure(self): - """Test get_users_list_memberships response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.lists_client, "get_users_list_memberships") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_users_owned_lists_request_structure(self): - """Test get_users_owned_lists request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.lists_client, "get_users_owned_lists") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/owned_lists" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_users_owned_lists: {e}") - - - def test_get_users_owned_lists_required_parameters(self): - """Test that get_users_owned_lists handles parameters correctly.""" - method = getattr(self.lists_client, "get_users_owned_lists") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_users_owned_lists_response_structure(self): - """Test get_users_owned_lists response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.lists_client, "get_users_owned_lists") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/xdk/python/tests/lists/test_pagination.py b/xdk/python/xdk/python/tests/lists/test_pagination.py deleted file mode 100644 index 10766150..00000000 --- a/xdk/python/xdk/python/tests/lists/test_pagination.py +++ /dev/null @@ -1,672 +0,0 @@ -""" -Auto-generated pagination tests for Lists client. - -This module contains tests that validate pagination functionality -using the Cursor class for methods that support pagination. - -Generated automatically - do not edit manually. -""" - -import pytest -from unittest.mock import Mock, patch -from xdk.lists.client import ListsClient -from xdk import Client, Cursor, cursor, PaginationError - - -class TestListsPagination: - """Test pagination functionality for ListsClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.lists_client = getattr(self.client, "lists") - - - def test_get_users_followed_lists_cursor_creation(self): - """Test that get_users_followed_lists can be used with Cursor.""" - method = getattr(self.lists_client, "get_users_followed_lists") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersFollowedLists should support pagination") - - - def test_get_users_followed_lists_cursor_pages(self): - """Test pagination with pages() for get_users_followed_lists.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.lists_client, "get_users_followed_lists") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_followed_lists_cursor_items(self): - """Test pagination with items() for get_users_followed_lists.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.lists_client, "get_users_followed_lists") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_followed_lists_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_followed_lists.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.lists_client, "get_users_followed_lists") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_users_list_memberships_cursor_creation(self): - """Test that get_users_list_memberships can be used with Cursor.""" - method = getattr(self.lists_client, "get_users_list_memberships") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersListMemberships should support pagination") - - - def test_get_users_list_memberships_cursor_pages(self): - """Test pagination with pages() for get_users_list_memberships.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.lists_client, "get_users_list_memberships") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_list_memberships_cursor_items(self): - """Test pagination with items() for get_users_list_memberships.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.lists_client, "get_users_list_memberships") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_list_memberships_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_list_memberships.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.lists_client, "get_users_list_memberships") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_users_owned_lists_cursor_creation(self): - """Test that get_users_owned_lists can be used with Cursor.""" - method = getattr(self.lists_client, "get_users_owned_lists") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersOwnedLists should support pagination") - - - def test_get_users_owned_lists_cursor_pages(self): - """Test pagination with pages() for get_users_owned_lists.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.lists_client, "get_users_owned_lists") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_owned_lists_cursor_items(self): - """Test pagination with items() for get_users_owned_lists.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.lists_client, "get_users_owned_lists") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_owned_lists_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_owned_lists.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.lists_client, "get_users_owned_lists") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_pagination_edge_cases(self): - """Test pagination edge cases.""" - with patch.object(self.client, "session") as mock_session: - # Test empty response - empty_response = Mock() - empty_response.status_code = 200 - # Use null/None for data to handle both list and object response types - empty_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - empty_response.raise_for_status.return_value = None - mock_session.get.return_value = empty_response - # Pick first paginatable method for testing - method = getattr(self.lists_client, "get_users_followed_lists") - test_cursor = cursor(method, "test_id", max_results=10) - # Should handle empty responses gracefully - pages = list(test_cursor.pages(1)) - assert len(pages) == 1, "Should get one page even if empty" - items = list(test_cursor.items(10)) - assert len(items) == 0, "Should get no items from empty response" - - - def test_non_paginatable_method_raises_error(self): - """Test that non-paginatable methods raise PaginationError.""" - # Create a mock method that doesn't support pagination - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def test_cursor_class_functionality(self): - """Test basic Cursor class functionality.""" - # Test that Cursor can be imported and instantiated - from xdk.paginator import Cursor - assert Cursor is not None - # Test cursor factory function - from xdk.paginator import cursor as cursor_factory - assert cursor_factory is not None diff --git a/xdk/python/xdk/python/tests/lists/test_structure.py b/xdk/python/xdk/python/tests/lists/test_structure.py deleted file mode 100644 index 7577ba5a..00000000 --- a/xdk/python/xdk/python/tests/lists/test_structure.py +++ /dev/null @@ -1,749 +0,0 @@ -""" -Auto-generated structural tests for Lists client. - -This module contains tests that validate the structure and API surface -of the Lists client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.lists.client import ListsClient -from xdk import Client - - -class TestListsStructure: - """Test the structure of ListsClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.lists_client = getattr(self.client, "lists") - - - def test_unfollow_list_exists(self): - """Test that unfollow_list method exists with correct signature.""" - # Check method exists - method = getattr(ListsClient, "unfollow_list", None) - assert method is not None, f"Method unfollow_list does not exist on ListsClient" - # Check method is callable - assert callable(method), f"unfollow_list is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"unfollow_list should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - "list_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from unfollow_list" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_unfollow_list_return_annotation(self): - """Test that unfollow_list has proper return type annotation.""" - method = getattr(ListsClient, "unfollow_list") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method unfollow_list should have return type annotation" - - - def test_unpin_list_exists(self): - """Test that unpin_list method exists with correct signature.""" - # Check method exists - method = getattr(ListsClient, "unpin_list", None) - assert method is not None, f"Method unpin_list does not exist on ListsClient" - # Check method is callable - assert callable(method), f"unpin_list is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"unpin_list should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - "list_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from unpin_list" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_unpin_list_return_annotation(self): - """Test that unpin_list has proper return type annotation.""" - method = getattr(ListsClient, "unpin_list") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method unpin_list should have return type annotation" - - - def test_add_lists_member_exists(self): - """Test that add_lists_member method exists with correct signature.""" - # Check method exists - method = getattr(ListsClient, "add_lists_member", None) - assert ( - method is not None - ), f"Method add_lists_member does not exist on ListsClient" - # Check method is callable - assert callable(method), f"add_lists_member is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"add_lists_member should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from add_lists_member" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_add_lists_member_return_annotation(self): - """Test that add_lists_member has proper return type annotation.""" - method = getattr(ListsClient, "add_lists_member") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method add_lists_member should have return type annotation" - - - def test_remove_lists_member_by_user_id_exists(self): - """Test that remove_lists_member_by_user_id method exists with correct signature.""" - # Check method exists - method = getattr(ListsClient, "remove_lists_member_by_user_id", None) - assert ( - method is not None - ), f"Method remove_lists_member_by_user_id does not exist on ListsClient" - # Check method is callable - assert callable(method), f"remove_lists_member_by_user_id is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"remove_lists_member_by_user_id should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - "user_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from remove_lists_member_by_user_id" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_remove_lists_member_by_user_id_return_annotation(self): - """Test that remove_lists_member_by_user_id has proper return type annotation.""" - method = getattr(ListsClient, "remove_lists_member_by_user_id") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method remove_lists_member_by_user_id should have return type annotation" - - - def test_get_users_followed_lists_exists(self): - """Test that get_users_followed_lists method exists with correct signature.""" - # Check method exists - method = getattr(ListsClient, "get_users_followed_lists", None) - assert ( - method is not None - ), f"Method get_users_followed_lists does not exist on ListsClient" - # Check method is callable - assert callable(method), f"get_users_followed_lists is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_followed_lists should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_users_followed_lists" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_users_followed_lists_return_annotation(self): - """Test that get_users_followed_lists has proper return type annotation.""" - method = getattr(ListsClient, "get_users_followed_lists") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_followed_lists should have return type annotation" - - - def test_get_users_followed_lists_pagination_params(self): - """Test that get_users_followed_lists has pagination parameters.""" - method = getattr(ListsClient, "get_users_followed_lists") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_followed_lists should have pagination parameters" - - - def test_follow_list_exists(self): - """Test that follow_list method exists with correct signature.""" - # Check method exists - method = getattr(ListsClient, "follow_list", None) - assert method is not None, f"Method follow_list does not exist on ListsClient" - # Check method is callable - assert callable(method), f"follow_list is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"follow_list should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from follow_list" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_follow_list_return_annotation(self): - """Test that follow_list has proper return type annotation.""" - method = getattr(ListsClient, "follow_list") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method follow_list should have return type annotation" - - - def test_create_lists_exists(self): - """Test that create_lists method exists with correct signature.""" - # Check method exists - method = getattr(ListsClient, "create_lists", None) - assert method is not None, f"Method create_lists does not exist on ListsClient" - # Check method is callable - assert callable(method), f"create_lists is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"create_lists should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from create_lists" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_create_lists_return_annotation(self): - """Test that create_lists has proper return type annotation.""" - method = getattr(ListsClient, "create_lists") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method create_lists should have return type annotation" - - - def test_get_lists_by_id_exists(self): - """Test that get_lists_by_id method exists with correct signature.""" - # Check method exists - method = getattr(ListsClient, "get_lists_by_id", None) - assert ( - method is not None - ), f"Method get_lists_by_id does not exist on ListsClient" - # Check method is callable - assert callable(method), f"get_lists_by_id is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_lists_by_id should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_lists_by_id" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_lists_by_id_return_annotation(self): - """Test that get_lists_by_id has proper return type annotation.""" - method = getattr(ListsClient, "get_lists_by_id") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_lists_by_id should have return type annotation" - - - def test_update_lists_exists(self): - """Test that update_lists method exists with correct signature.""" - # Check method exists - method = getattr(ListsClient, "update_lists", None) - assert method is not None, f"Method update_lists does not exist on ListsClient" - # Check method is callable - assert callable(method), f"update_lists is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"update_lists should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from update_lists" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_update_lists_return_annotation(self): - """Test that update_lists has proper return type annotation.""" - method = getattr(ListsClient, "update_lists") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method update_lists should have return type annotation" - - - def test_delete_lists_exists(self): - """Test that delete_lists method exists with correct signature.""" - # Check method exists - method = getattr(ListsClient, "delete_lists", None) - assert method is not None, f"Method delete_lists does not exist on ListsClient" - # Check method is callable - assert callable(method), f"delete_lists is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"delete_lists should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from delete_lists" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_delete_lists_return_annotation(self): - """Test that delete_lists has proper return type annotation.""" - method = getattr(ListsClient, "delete_lists") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method delete_lists should have return type annotation" - - - def test_get_users_pinned_lists_exists(self): - """Test that get_users_pinned_lists method exists with correct signature.""" - # Check method exists - method = getattr(ListsClient, "get_users_pinned_lists", None) - assert ( - method is not None - ), f"Method get_users_pinned_lists does not exist on ListsClient" - # Check method is callable - assert callable(method), f"get_users_pinned_lists is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_pinned_lists should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_users_pinned_lists" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_users_pinned_lists_return_annotation(self): - """Test that get_users_pinned_lists has proper return type annotation.""" - method = getattr(ListsClient, "get_users_pinned_lists") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_pinned_lists should have return type annotation" - - - def test_pin_list_exists(self): - """Test that pin_list method exists with correct signature.""" - # Check method exists - method = getattr(ListsClient, "pin_list", None) - assert method is not None, f"Method pin_list does not exist on ListsClient" - # Check method is callable - assert callable(method), f"pin_list is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"pin_list should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from pin_list" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_pin_list_return_annotation(self): - """Test that pin_list has proper return type annotation.""" - method = getattr(ListsClient, "pin_list") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method pin_list should have return type annotation" - - - def test_get_users_list_memberships_exists(self): - """Test that get_users_list_memberships method exists with correct signature.""" - # Check method exists - method = getattr(ListsClient, "get_users_list_memberships", None) - assert ( - method is not None - ), f"Method get_users_list_memberships does not exist on ListsClient" - # Check method is callable - assert callable(method), f"get_users_list_memberships is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_list_memberships should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_users_list_memberships" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_users_list_memberships_return_annotation(self): - """Test that get_users_list_memberships has proper return type annotation.""" - method = getattr(ListsClient, "get_users_list_memberships") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_list_memberships should have return type annotation" - - - def test_get_users_list_memberships_pagination_params(self): - """Test that get_users_list_memberships has pagination parameters.""" - method = getattr(ListsClient, "get_users_list_memberships") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_list_memberships should have pagination parameters" - - - def test_get_users_owned_lists_exists(self): - """Test that get_users_owned_lists method exists with correct signature.""" - # Check method exists - method = getattr(ListsClient, "get_users_owned_lists", None) - assert ( - method is not None - ), f"Method get_users_owned_lists does not exist on ListsClient" - # Check method is callable - assert callable(method), f"get_users_owned_lists is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_owned_lists should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_users_owned_lists" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_users_owned_lists_return_annotation(self): - """Test that get_users_owned_lists has proper return type annotation.""" - method = getattr(ListsClient, "get_users_owned_lists") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_owned_lists should have return type annotation" - - - def test_get_users_owned_lists_pagination_params(self): - """Test that get_users_owned_lists has pagination parameters.""" - method = getattr(ListsClient, "get_users_owned_lists") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_owned_lists should have pagination parameters" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "unfollow_list", - "unpin_list", - "add_lists_member", - "remove_lists_member_by_user_id", - "get_users_followed_lists", - "follow_list", - "create_lists", - "get_lists_by_id", - "update_lists", - "delete_lists", - "get_users_pinned_lists", - "pin_list", - "get_users_list_memberships", - "get_users_owned_lists", - ] - for expected_method in expected_methods: - assert hasattr( - ListsClient, expected_method - ), f"Expected method '{expected_method}' not found on ListsClient" - assert callable( - getattr(ListsClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/xdk/python/tests/media/__init__.py b/xdk/python/xdk/python/tests/media/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/media/test_contracts.py b/xdk/python/xdk/python/tests/media/test_contracts.py deleted file mode 100644 index b8b703bc..00000000 --- a/xdk/python/xdk/python/tests/media/test_contracts.py +++ /dev/null @@ -1,1003 +0,0 @@ -""" -Auto-generated contract tests for Media client. - -This module contains tests that validate the request/response contracts -of the Media client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.media.client import MediaClient -from xdk import Client - - -class TestMediaContracts: - """Test the API contracts of MediaClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.media_client = getattr(self.client, "media") - - - def test_create_media_subtitles_request_structure(self): - """Test create_media_subtitles request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Import and create proper request model instance - from xdk.media.models import CreatemediasubtitlesRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatemediasubtitlesRequest() - # Call the method - try: - method = getattr(self.media_client, "create_media_subtitles") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/media/subtitles" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for create_media_subtitles: {e}") - - - def test_create_media_subtitles_required_parameters(self): - """Test that create_media_subtitles handles parameters correctly.""" - method = getattr(self.media_client, "create_media_subtitles") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_create_media_subtitles_response_structure(self): - """Test create_media_subtitles response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Import and create proper request model instance - from xdk.media.models import CreatemediasubtitlesRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatemediasubtitlesRequest() - # Call method and verify response structure - method = getattr(self.media_client, "create_media_subtitles") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_delete_media_subtitles_request_structure(self): - """Test delete_media_subtitles request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Import and create proper request model instance - from xdk.media.models import DeletemediasubtitlesRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = DeletemediasubtitlesRequest() - # Call the method - try: - method = getattr(self.media_client, "delete_media_subtitles") - result = method(**kwargs) - # Verify the request was made - mock_session.delete.assert_called_once() - # Verify request structure - call_args = mock_session.delete.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/media/subtitles" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for delete_media_subtitles: {e}") - - - def test_delete_media_subtitles_required_parameters(self): - """Test that delete_media_subtitles handles parameters correctly.""" - method = getattr(self.media_client, "delete_media_subtitles") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_delete_media_subtitles_response_structure(self): - """Test delete_media_subtitles response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Import and create proper request model instance - from xdk.media.models import DeletemediasubtitlesRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = DeletemediasubtitlesRequest() - # Call method and verify response structure - method = getattr(self.media_client, "delete_media_subtitles") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_finalize_media_upload_request_structure(self): - """Test finalize_media_upload request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.media_client, "finalize_media_upload") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/media/upload/{id}/finalize" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for finalize_media_upload: {e}") - - - def test_finalize_media_upload_required_parameters(self): - """Test that finalize_media_upload handles parameters correctly.""" - method = getattr(self.media_client, "finalize_media_upload") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_finalize_media_upload_response_structure(self): - """Test finalize_media_upload response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.media_client, "finalize_media_upload") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_media_by_media_key_request_structure(self): - """Test get_media_by_media_key request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["media_key"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.media_client, "get_media_by_media_key") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/media/{media_key}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_media_by_media_key: {e}") - - - def test_get_media_by_media_key_required_parameters(self): - """Test that get_media_by_media_key handles parameters correctly.""" - method = getattr(self.media_client, "get_media_by_media_key") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_media_by_media_key_response_structure(self): - """Test get_media_by_media_key response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["media_key"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.media_client, "get_media_by_media_key") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_media_by_media_keys_request_structure(self): - """Test get_media_by_media_keys request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["media_keys"] = ["test_item"] - # Add request body if required - # Call the method - try: - method = getattr(self.media_client, "get_media_by_media_keys") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/media" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_media_by_media_keys: {e}") - - - def test_get_media_by_media_keys_required_parameters(self): - """Test that get_media_by_media_keys handles parameters correctly.""" - method = getattr(self.media_client, "get_media_by_media_keys") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_media_by_media_keys_response_structure(self): - """Test get_media_by_media_keys response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["media_keys"] = ["test"] - # Add request body if required - # Call method and verify response structure - method = getattr(self.media_client, "get_media_by_media_keys") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_initialize_media_upload_request_structure(self): - """Test initialize_media_upload request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Import and create proper request model instance - from xdk.media.models import InitializemediauploadRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = InitializemediauploadRequest() - # Call the method - try: - method = getattr(self.media_client, "initialize_media_upload") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/media/upload/initialize" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for initialize_media_upload: {e}") - - - def test_initialize_media_upload_required_parameters(self): - """Test that initialize_media_upload handles parameters correctly.""" - method = getattr(self.media_client, "initialize_media_upload") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_initialize_media_upload_response_structure(self): - """Test initialize_media_upload response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Import and create proper request model instance - from xdk.media.models import InitializemediauploadRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = InitializemediauploadRequest() - # Call method and verify response structure - method = getattr(self.media_client, "initialize_media_upload") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_media_upload_status_request_structure(self): - """Test get_media_upload_status request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["media_id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.media_client, "get_media_upload_status") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/media/upload" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_media_upload_status: {e}") - - - def test_get_media_upload_status_required_parameters(self): - """Test that get_media_upload_status handles parameters correctly.""" - method = getattr(self.media_client, "get_media_upload_status") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_media_upload_status_response_structure(self): - """Test get_media_upload_status response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["media_id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.media_client, "get_media_upload_status") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_media_upload_request_structure(self): - """Test media_upload request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Import and create proper request model instance - from xdk.media.models import MediauploadRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = MediauploadRequest() - # Call the method - try: - method = getattr(self.media_client, "media_upload") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/media/upload" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for media_upload: {e}") - - - def test_media_upload_required_parameters(self): - """Test that media_upload handles parameters correctly.""" - method = getattr(self.media_client, "media_upload") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_media_upload_response_structure(self): - """Test media_upload response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Import and create proper request model instance - from xdk.media.models import MediauploadRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = MediauploadRequest() - # Call method and verify response structure - method = getattr(self.media_client, "media_upload") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_media_analytics_request_structure(self): - """Test get_media_analytics request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["media_keys"] = ["test_item"] - kwargs["end_time"] = "test_end_time" - kwargs["start_time"] = "test_start_time" - kwargs["granularity"] = "test_granularity" - # Add request body if required - # Call the method - try: - method = getattr(self.media_client, "get_media_analytics") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/media/analytics" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_media_analytics: {e}") - - - def test_get_media_analytics_required_parameters(self): - """Test that get_media_analytics handles parameters correctly.""" - method = getattr(self.media_client, "get_media_analytics") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_media_analytics_response_structure(self): - """Test get_media_analytics response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["media_keys"] = ["test"] - kwargs["end_time"] = "test_value" - kwargs["start_time"] = "test_value" - kwargs["granularity"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.media_client, "get_media_analytics") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_create_media_metadata_request_structure(self): - """Test create_media_metadata request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Import and create proper request model instance - from xdk.media.models import CreatemediametadataRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatemediametadataRequest() - # Call the method - try: - method = getattr(self.media_client, "create_media_metadata") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/media/metadata" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for create_media_metadata: {e}") - - - def test_create_media_metadata_required_parameters(self): - """Test that create_media_metadata handles parameters correctly.""" - method = getattr(self.media_client, "create_media_metadata") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_create_media_metadata_response_structure(self): - """Test create_media_metadata response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Import and create proper request model instance - from xdk.media.models import CreatemediametadataRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatemediametadataRequest() - # Call method and verify response structure - method = getattr(self.media_client, "create_media_metadata") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_append_media_upload_request_structure(self): - """Test append_media_upload request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Import and create proper request model instance - from xdk.media.models import AppendmediauploadRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = AppendmediauploadRequest() - # Call the method - try: - method = getattr(self.media_client, "append_media_upload") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/media/upload/{id}/append" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for append_media_upload: {e}") - - - def test_append_media_upload_required_parameters(self): - """Test that append_media_upload handles parameters correctly.""" - method = getattr(self.media_client, "append_media_upload") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_append_media_upload_response_structure(self): - """Test append_media_upload response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Import and create proper request model instance - from xdk.media.models import AppendmediauploadRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = AppendmediauploadRequest() - # Call method and verify response structure - method = getattr(self.media_client, "append_media_upload") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/xdk/python/tests/media/test_generic.py b/xdk/python/xdk/python/tests/media/test_generic.py deleted file mode 100644 index 20e5e453..00000000 --- a/xdk/python/xdk/python/tests/media/test_generic.py +++ /dev/null @@ -1,122 +0,0 @@ -""" -Auto-generated generic tests for Media client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.media.client import MediaClient -from xdk import Client - - -class TestMediaGeneric: - """Generic tests for MediaClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.media_client = getattr(self.client, "media") - - - def test_client_exists(self): - """Test that MediaClient class exists and is importable.""" - assert MediaClient is not None - assert hasattr(MediaClient, "__name__") - assert MediaClient.__name__ == "MediaClient" - - - def test_client_initialization(self): - """Test that MediaClient can be initialized properly.""" - assert self.media_client is not None - assert isinstance(self.media_client, MediaClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(MediaClient) - if not name.startswith("_") and callable(getattr(MediaClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.media_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "media") - # Client should have standard Python object features - assert hasattr(self.media_client, "__class__") - assert hasattr(self.media_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.media_client) - if not name.startswith("_") and callable(getattr(self.media_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"MediaClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(MediaClient) - if not name.startswith("_") and callable(getattr(MediaClient, name)) - ] - for method_name in public_methods: - method = getattr(MediaClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/xdk/python/tests/media/test_structure.py b/xdk/python/xdk/python/tests/media/test_structure.py deleted file mode 100644 index 35c02908..00000000 --- a/xdk/python/xdk/python/tests/media/test_structure.py +++ /dev/null @@ -1,557 +0,0 @@ -""" -Auto-generated structural tests for Media client. - -This module contains tests that validate the structure and API surface -of the Media client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.media.client import MediaClient -from xdk import Client - - -class TestMediaStructure: - """Test the structure of MediaClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.media_client = getattr(self.client, "media") - - - def test_create_media_subtitles_exists(self): - """Test that create_media_subtitles method exists with correct signature.""" - # Check method exists - method = getattr(MediaClient, "create_media_subtitles", None) - assert ( - method is not None - ), f"Method create_media_subtitles does not exist on MediaClient" - # Check method is callable - assert callable(method), f"create_media_subtitles is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"create_media_subtitles should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from create_media_subtitles" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_create_media_subtitles_return_annotation(self): - """Test that create_media_subtitles has proper return type annotation.""" - method = getattr(MediaClient, "create_media_subtitles") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method create_media_subtitles should have return type annotation" - - - def test_delete_media_subtitles_exists(self): - """Test that delete_media_subtitles method exists with correct signature.""" - # Check method exists - method = getattr(MediaClient, "delete_media_subtitles", None) - assert ( - method is not None - ), f"Method delete_media_subtitles does not exist on MediaClient" - # Check method is callable - assert callable(method), f"delete_media_subtitles is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"delete_media_subtitles should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from delete_media_subtitles" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_delete_media_subtitles_return_annotation(self): - """Test that delete_media_subtitles has proper return type annotation.""" - method = getattr(MediaClient, "delete_media_subtitles") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method delete_media_subtitles should have return type annotation" - - - def test_finalize_media_upload_exists(self): - """Test that finalize_media_upload method exists with correct signature.""" - # Check method exists - method = getattr(MediaClient, "finalize_media_upload", None) - assert ( - method is not None - ), f"Method finalize_media_upload does not exist on MediaClient" - # Check method is callable - assert callable(method), f"finalize_media_upload is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"finalize_media_upload should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from finalize_media_upload" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_finalize_media_upload_return_annotation(self): - """Test that finalize_media_upload has proper return type annotation.""" - method = getattr(MediaClient, "finalize_media_upload") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method finalize_media_upload should have return type annotation" - - - def test_get_media_by_media_key_exists(self): - """Test that get_media_by_media_key method exists with correct signature.""" - # Check method exists - method = getattr(MediaClient, "get_media_by_media_key", None) - assert ( - method is not None - ), f"Method get_media_by_media_key does not exist on MediaClient" - # Check method is callable - assert callable(method), f"get_media_by_media_key is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_media_by_media_key should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "media_key", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_media_by_media_key" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_media_by_media_key_return_annotation(self): - """Test that get_media_by_media_key has proper return type annotation.""" - method = getattr(MediaClient, "get_media_by_media_key") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_media_by_media_key should have return type annotation" - - - def test_get_media_by_media_keys_exists(self): - """Test that get_media_by_media_keys method exists with correct signature.""" - # Check method exists - method = getattr(MediaClient, "get_media_by_media_keys", None) - assert ( - method is not None - ), f"Method get_media_by_media_keys does not exist on MediaClient" - # Check method is callable - assert callable(method), f"get_media_by_media_keys is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_media_by_media_keys should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "media_keys", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_media_by_media_keys" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_media_by_media_keys_return_annotation(self): - """Test that get_media_by_media_keys has proper return type annotation.""" - method = getattr(MediaClient, "get_media_by_media_keys") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_media_by_media_keys should have return type annotation" - - - def test_initialize_media_upload_exists(self): - """Test that initialize_media_upload method exists with correct signature.""" - # Check method exists - method = getattr(MediaClient, "initialize_media_upload", None) - assert ( - method is not None - ), f"Method initialize_media_upload does not exist on MediaClient" - # Check method is callable - assert callable(method), f"initialize_media_upload is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"initialize_media_upload should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from initialize_media_upload" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_initialize_media_upload_return_annotation(self): - """Test that initialize_media_upload has proper return type annotation.""" - method = getattr(MediaClient, "initialize_media_upload") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method initialize_media_upload should have return type annotation" - - - def test_get_media_upload_status_exists(self): - """Test that get_media_upload_status method exists with correct signature.""" - # Check method exists - method = getattr(MediaClient, "get_media_upload_status", None) - assert ( - method is not None - ), f"Method get_media_upload_status does not exist on MediaClient" - # Check method is callable - assert callable(method), f"get_media_upload_status is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_media_upload_status should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "media_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_media_upload_status" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "command", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_media_upload_status_return_annotation(self): - """Test that get_media_upload_status has proper return type annotation.""" - method = getattr(MediaClient, "get_media_upload_status") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_media_upload_status should have return type annotation" - - - def test_media_upload_exists(self): - """Test that media_upload method exists with correct signature.""" - # Check method exists - method = getattr(MediaClient, "media_upload", None) - assert method is not None, f"Method media_upload does not exist on MediaClient" - # Check method is callable - assert callable(method), f"media_upload is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"media_upload should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from media_upload" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_media_upload_return_annotation(self): - """Test that media_upload has proper return type annotation.""" - method = getattr(MediaClient, "media_upload") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method media_upload should have return type annotation" - - - def test_get_media_analytics_exists(self): - """Test that get_media_analytics method exists with correct signature.""" - # Check method exists - method = getattr(MediaClient, "get_media_analytics", None) - assert ( - method is not None - ), f"Method get_media_analytics does not exist on MediaClient" - # Check method is callable - assert callable(method), f"get_media_analytics is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_media_analytics should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "media_keys", - "end_time", - "start_time", - "granularity", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_media_analytics" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_media_analytics_return_annotation(self): - """Test that get_media_analytics has proper return type annotation.""" - method = getattr(MediaClient, "get_media_analytics") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_media_analytics should have return type annotation" - - - def test_create_media_metadata_exists(self): - """Test that create_media_metadata method exists with correct signature.""" - # Check method exists - method = getattr(MediaClient, "create_media_metadata", None) - assert ( - method is not None - ), f"Method create_media_metadata does not exist on MediaClient" - # Check method is callable - assert callable(method), f"create_media_metadata is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"create_media_metadata should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from create_media_metadata" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_create_media_metadata_return_annotation(self): - """Test that create_media_metadata has proper return type annotation.""" - method = getattr(MediaClient, "create_media_metadata") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method create_media_metadata should have return type annotation" - - - def test_append_media_upload_exists(self): - """Test that append_media_upload method exists with correct signature.""" - # Check method exists - method = getattr(MediaClient, "append_media_upload", None) - assert ( - method is not None - ), f"Method append_media_upload does not exist on MediaClient" - # Check method is callable - assert callable(method), f"append_media_upload is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"append_media_upload should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from append_media_upload" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_append_media_upload_return_annotation(self): - """Test that append_media_upload has proper return type annotation.""" - method = getattr(MediaClient, "append_media_upload") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method append_media_upload should have return type annotation" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "create_media_subtitles", - "delete_media_subtitles", - "finalize_media_upload", - "get_media_by_media_key", - "get_media_by_media_keys", - "initialize_media_upload", - "get_media_upload_status", - "media_upload", - "get_media_analytics", - "create_media_metadata", - "append_media_upload", - ] - for expected_method in expected_methods: - assert hasattr( - MediaClient, expected_method - ), f"Expected method '{expected_method}' not found on MediaClient" - assert callable( - getattr(MediaClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/xdk/python/tests/spaces/__init__.py b/xdk/python/xdk/python/tests/spaces/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/spaces/test_contracts.py b/xdk/python/xdk/python/tests/spaces/test_contracts.py deleted file mode 100644 index 33c863ed..00000000 --- a/xdk/python/xdk/python/tests/spaces/test_contracts.py +++ /dev/null @@ -1,534 +0,0 @@ -""" -Auto-generated contract tests for Spaces client. - -This module contains tests that validate the request/response contracts -of the Spaces client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.spaces.client import SpacesClient -from xdk import Client - - -class TestSpacesContracts: - """Test the API contracts of SpacesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.spaces_client = getattr(self.client, "spaces") - - - def test_get_spaces_posts_request_structure(self): - """Test get_spaces_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_id" - # Add request body if required - # Call the method - try: - method = getattr(self.spaces_client, "get_spaces_posts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/spaces/{id}/tweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_spaces_posts: {e}") - - - def test_get_spaces_posts_required_parameters(self): - """Test that get_spaces_posts handles parameters correctly.""" - method = getattr(self.spaces_client, "get_spaces_posts") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_spaces_posts_response_structure(self): - """Test get_spaces_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.spaces_client, "get_spaces_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_search_spaces_request_structure(self): - """Test search_spaces request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["query"] = "test_query" - # Add request body if required - # Call the method - try: - method = getattr(self.spaces_client, "search_spaces") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/spaces/search" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for search_spaces: {e}") - - - def test_search_spaces_required_parameters(self): - """Test that search_spaces handles parameters correctly.""" - method = getattr(self.spaces_client, "search_spaces") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_search_spaces_response_structure(self): - """Test search_spaces response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["query"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.spaces_client, "search_spaces") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_spaces_by_creator_ids_request_structure(self): - """Test get_spaces_by_creator_ids request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["user_ids"] = ["test_item"] - # Add request body if required - # Call the method - try: - method = getattr(self.spaces_client, "get_spaces_by_creator_ids") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/spaces/by/creator_ids" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_spaces_by_creator_ids: {e}") - - - def test_get_spaces_by_creator_ids_required_parameters(self): - """Test that get_spaces_by_creator_ids handles parameters correctly.""" - method = getattr(self.spaces_client, "get_spaces_by_creator_ids") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_spaces_by_creator_ids_response_structure(self): - """Test get_spaces_by_creator_ids response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["user_ids"] = ["test"] - # Add request body if required - # Call method and verify response structure - method = getattr(self.spaces_client, "get_spaces_by_creator_ids") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_spaces_buyers_request_structure(self): - """Test get_spaces_buyers request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_id" - # Add request body if required - # Call the method - try: - method = getattr(self.spaces_client, "get_spaces_buyers") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/spaces/{id}/buyers" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_spaces_buyers: {e}") - - - def test_get_spaces_buyers_required_parameters(self): - """Test that get_spaces_buyers handles parameters correctly.""" - method = getattr(self.spaces_client, "get_spaces_buyers") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_spaces_buyers_response_structure(self): - """Test get_spaces_buyers response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.spaces_client, "get_spaces_buyers") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_spaces_by_ids_request_structure(self): - """Test get_spaces_by_ids request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["ids"] = ["test_item"] - # Add request body if required - # Call the method - try: - method = getattr(self.spaces_client, "get_spaces_by_ids") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/spaces" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_spaces_by_ids: {e}") - - - def test_get_spaces_by_ids_required_parameters(self): - """Test that get_spaces_by_ids handles parameters correctly.""" - method = getattr(self.spaces_client, "get_spaces_by_ids") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_spaces_by_ids_response_structure(self): - """Test get_spaces_by_ids response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["ids"] = ["test"] - # Add request body if required - # Call method and verify response structure - method = getattr(self.spaces_client, "get_spaces_by_ids") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_spaces_by_id_request_structure(self): - """Test get_spaces_by_id request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_id" - # Add request body if required - # Call the method - try: - method = getattr(self.spaces_client, "get_spaces_by_id") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/spaces/{id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_spaces_by_id: {e}") - - - def test_get_spaces_by_id_required_parameters(self): - """Test that get_spaces_by_id handles parameters correctly.""" - method = getattr(self.spaces_client, "get_spaces_by_id") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_spaces_by_id_response_structure(self): - """Test get_spaces_by_id response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.spaces_client, "get_spaces_by_id") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/xdk/python/tests/spaces/test_generic.py b/xdk/python/xdk/python/tests/spaces/test_generic.py deleted file mode 100644 index 8e798843..00000000 --- a/xdk/python/xdk/python/tests/spaces/test_generic.py +++ /dev/null @@ -1,122 +0,0 @@ -""" -Auto-generated generic tests for Spaces client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.spaces.client import SpacesClient -from xdk import Client - - -class TestSpacesGeneric: - """Generic tests for SpacesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.spaces_client = getattr(self.client, "spaces") - - - def test_client_exists(self): - """Test that SpacesClient class exists and is importable.""" - assert SpacesClient is not None - assert hasattr(SpacesClient, "__name__") - assert SpacesClient.__name__ == "SpacesClient" - - - def test_client_initialization(self): - """Test that SpacesClient can be initialized properly.""" - assert self.spaces_client is not None - assert isinstance(self.spaces_client, SpacesClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(SpacesClient) - if not name.startswith("_") and callable(getattr(SpacesClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.spaces_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "spaces") - # Client should have standard Python object features - assert hasattr(self.spaces_client, "__class__") - assert hasattr(self.spaces_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.spaces_client) - if not name.startswith("_") and callable(getattr(self.spaces_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"SpacesClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(SpacesClient) - if not name.startswith("_") and callable(getattr(SpacesClient, name)) - ] - for method_name in public_methods: - method = getattr(SpacesClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/xdk/python/tests/spaces/test_pagination.py b/xdk/python/xdk/python/tests/spaces/test_pagination.py deleted file mode 100644 index 6682480d..00000000 --- a/xdk/python/xdk/python/tests/spaces/test_pagination.py +++ /dev/null @@ -1,382 +0,0 @@ -""" -Auto-generated pagination tests for Spaces client. - -This module contains tests that validate pagination functionality -using the Cursor class for methods that support pagination. - -Generated automatically - do not edit manually. -""" - -import pytest -from unittest.mock import Mock, patch -from xdk.spaces.client import SpacesClient -from xdk import Client, Cursor, cursor, PaginationError - - -class TestSpacesPagination: - """Test pagination functionality for SpacesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.spaces_client = getattr(self.client, "spaces") - - - def test_get_spaces_buyers_cursor_creation(self): - """Test that get_spaces_buyers can be used with Cursor.""" - method = getattr(self.spaces_client, "get_spaces_buyers") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getSpacesBuyers should support pagination") - - - def test_get_spaces_buyers_cursor_pages(self): - """Test pagination with pages() for get_spaces_buyers.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.spaces_client, "get_spaces_buyers") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_spaces_buyers_cursor_items(self): - """Test pagination with items() for get_spaces_buyers.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.spaces_client, "get_spaces_buyers") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_spaces_buyers_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_spaces_buyers.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.spaces_client, "get_spaces_buyers") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_pagination_edge_cases(self): - """Test pagination edge cases.""" - with patch.object(self.client, "session") as mock_session: - # Test empty response - empty_response = Mock() - empty_response.status_code = 200 - # Use null/None for data to handle both list and object response types - empty_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - empty_response.raise_for_status.return_value = None - mock_session.get.return_value = empty_response - # Pick first paginatable method for testing - method = getattr(self.spaces_client, "get_spaces_buyers") - test_cursor = cursor(method, "test_id", max_results=10) - # Should handle empty responses gracefully - pages = list(test_cursor.pages(1)) - assert len(pages) == 1, "Should get one page even if empty" - items = list(test_cursor.items(10)) - assert len(items) == 0, "Should get no items from empty response" - - - def test_non_paginatable_method_raises_error(self): - """Test that non-paginatable methods raise PaginationError.""" - # Create a mock method that doesn't support pagination - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def test_cursor_class_functionality(self): - """Test basic Cursor class functionality.""" - # Test that Cursor can be imported and instantiated - from xdk.paginator import Cursor - assert Cursor is not None - # Test cursor factory function - from xdk.paginator import cursor as cursor_factory - assert cursor_factory is not None diff --git a/xdk/python/xdk/python/tests/spaces/test_structure.py b/xdk/python/xdk/python/tests/spaces/test_structure.py deleted file mode 100644 index fb357d25..00000000 --- a/xdk/python/xdk/python/tests/spaces/test_structure.py +++ /dev/null @@ -1,351 +0,0 @@ -""" -Auto-generated structural tests for Spaces client. - -This module contains tests that validate the structure and API surface -of the Spaces client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.spaces.client import SpacesClient -from xdk import Client - - -class TestSpacesStructure: - """Test the structure of SpacesClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.spaces_client = getattr(self.client, "spaces") - - - def test_get_spaces_posts_exists(self): - """Test that get_spaces_posts method exists with correct signature.""" - # Check method exists - method = getattr(SpacesClient, "get_spaces_posts", None) - assert ( - method is not None - ), f"Method get_spaces_posts does not exist on SpacesClient" - # Check method is callable - assert callable(method), f"get_spaces_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_spaces_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_spaces_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_spaces_posts_return_annotation(self): - """Test that get_spaces_posts has proper return type annotation.""" - method = getattr(SpacesClient, "get_spaces_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_spaces_posts should have return type annotation" - - - def test_search_spaces_exists(self): - """Test that search_spaces method exists with correct signature.""" - # Check method exists - method = getattr(SpacesClient, "search_spaces", None) - assert ( - method is not None - ), f"Method search_spaces does not exist on SpacesClient" - # Check method is callable - assert callable(method), f"search_spaces is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"search_spaces should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "query", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from search_spaces" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "state", - "max_results", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_search_spaces_return_annotation(self): - """Test that search_spaces has proper return type annotation.""" - method = getattr(SpacesClient, "search_spaces") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method search_spaces should have return type annotation" - - - def test_get_spaces_by_creator_ids_exists(self): - """Test that get_spaces_by_creator_ids method exists with correct signature.""" - # Check method exists - method = getattr(SpacesClient, "get_spaces_by_creator_ids", None) - assert ( - method is not None - ), f"Method get_spaces_by_creator_ids does not exist on SpacesClient" - # Check method is callable - assert callable(method), f"get_spaces_by_creator_ids is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_spaces_by_creator_ids should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "user_ids", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_spaces_by_creator_ids" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_spaces_by_creator_ids_return_annotation(self): - """Test that get_spaces_by_creator_ids has proper return type annotation.""" - method = getattr(SpacesClient, "get_spaces_by_creator_ids") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_spaces_by_creator_ids should have return type annotation" - - - def test_get_spaces_buyers_exists(self): - """Test that get_spaces_buyers method exists with correct signature.""" - # Check method exists - method = getattr(SpacesClient, "get_spaces_buyers", None) - assert ( - method is not None - ), f"Method get_spaces_buyers does not exist on SpacesClient" - # Check method is callable - assert callable(method), f"get_spaces_buyers is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_spaces_buyers should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_spaces_buyers" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "pagination_token", - "max_results", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_spaces_buyers_return_annotation(self): - """Test that get_spaces_buyers has proper return type annotation.""" - method = getattr(SpacesClient, "get_spaces_buyers") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_spaces_buyers should have return type annotation" - - - def test_get_spaces_buyers_pagination_params(self): - """Test that get_spaces_buyers has pagination parameters.""" - method = getattr(SpacesClient, "get_spaces_buyers") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_spaces_buyers should have pagination parameters" - - - def test_get_spaces_by_ids_exists(self): - """Test that get_spaces_by_ids method exists with correct signature.""" - # Check method exists - method = getattr(SpacesClient, "get_spaces_by_ids", None) - assert ( - method is not None - ), f"Method get_spaces_by_ids does not exist on SpacesClient" - # Check method is callable - assert callable(method), f"get_spaces_by_ids is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_spaces_by_ids should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "ids", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_spaces_by_ids" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_spaces_by_ids_return_annotation(self): - """Test that get_spaces_by_ids has proper return type annotation.""" - method = getattr(SpacesClient, "get_spaces_by_ids") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_spaces_by_ids should have return type annotation" - - - def test_get_spaces_by_id_exists(self): - """Test that get_spaces_by_id method exists with correct signature.""" - # Check method exists - method = getattr(SpacesClient, "get_spaces_by_id", None) - assert ( - method is not None - ), f"Method get_spaces_by_id does not exist on SpacesClient" - # Check method is callable - assert callable(method), f"get_spaces_by_id is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_spaces_by_id should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_spaces_by_id" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_spaces_by_id_return_annotation(self): - """Test that get_spaces_by_id has proper return type annotation.""" - method = getattr(SpacesClient, "get_spaces_by_id") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_spaces_by_id should have return type annotation" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "get_spaces_posts", - "search_spaces", - "get_spaces_by_creator_ids", - "get_spaces_buyers", - "get_spaces_by_ids", - "get_spaces_by_id", - ] - for expected_method in expected_methods: - assert hasattr( - SpacesClient, expected_method - ), f"Expected method '{expected_method}' not found on SpacesClient" - assert callable( - getattr(SpacesClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/xdk/python/tests/stream/__init__.py b/xdk/python/xdk/python/tests/stream/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/stream/test_contracts.py b/xdk/python/xdk/python/tests/stream/test_contracts.py deleted file mode 100644 index da77c165..00000000 --- a/xdk/python/xdk/python/tests/stream/test_contracts.py +++ /dev/null @@ -1,1463 +0,0 @@ -""" -Auto-generated contract tests for Stream client. - -This module contains tests that validate the request/response contracts -of the Stream client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.stream.client import StreamClient -from xdk import Client - - -class TestStreamContracts: - """Test the API contracts of StreamClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.stream_client = getattr(self.client, "stream") - - - def test_stream_likes_firehose_request_structure(self): - """Test stream_likes_firehose request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.stream_client, "stream_likes_firehose") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/likes/firehose/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_likes_firehose: {e}") - - - def test_stream_likes_firehose_required_parameters(self): - """Test that stream_likes_firehose handles parameters correctly.""" - method = getattr(self.stream_client, "stream_likes_firehose") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_likes_firehose_response_structure(self): - """Test stream_likes_firehose response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.stream_client, "stream_likes_firehose") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_sample10_request_structure(self): - """Test stream_posts_sample10 request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.stream_client, "stream_posts_sample10") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/sample10/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_sample10: {e}") - - - def test_stream_posts_sample10_required_parameters(self): - """Test that stream_posts_sample10 handles parameters correctly.""" - method = getattr(self.stream_client, "stream_posts_sample10") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_sample10_response_structure(self): - """Test stream_posts_sample10 response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.stream_client, "stream_posts_sample10") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_likes_sample10_request_structure(self): - """Test stream_likes_sample10 request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.stream_client, "stream_likes_sample10") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/likes/sample10/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_likes_sample10: {e}") - - - def test_stream_likes_sample10_required_parameters(self): - """Test that stream_likes_sample10 handles parameters correctly.""" - method = getattr(self.stream_client, "stream_likes_sample10") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_likes_sample10_response_structure(self): - """Test stream_likes_sample10 response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.stream_client, "stream_likes_sample10") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_firehose_request_structure(self): - """Test stream_posts_firehose request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.stream_client, "stream_posts_firehose") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/firehose/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose: {e}") - - - def test_stream_posts_firehose_required_parameters(self): - """Test that stream_posts_firehose handles parameters correctly.""" - method = getattr(self.stream_client, "stream_posts_firehose") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_firehose_response_structure(self): - """Test stream_posts_firehose response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.stream_client, "stream_posts_firehose") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_rule_counts_request_structure(self): - """Test get_rule_counts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.stream_client, "get_rule_counts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/search/stream/rules/counts" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_rule_counts: {e}") - - - def test_get_rule_counts_required_parameters(self): - """Test that get_rule_counts handles parameters correctly.""" - method = getattr(self.stream_client, "get_rule_counts") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_get_rule_counts_response_structure(self): - """Test get_rule_counts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.stream_client, "get_rule_counts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_firehose_en_request_structure(self): - """Test stream_posts_firehose_en request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.stream_client, "stream_posts_firehose_en") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/firehose/stream/lang/en" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose_en: {e}") - - - def test_stream_posts_firehose_en_required_parameters(self): - """Test that stream_posts_firehose_en handles parameters correctly.""" - method = getattr(self.stream_client, "stream_posts_firehose_en") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_firehose_en_response_structure(self): - """Test stream_posts_firehose_en response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.stream_client, "stream_posts_firehose_en") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_likes_compliance_request_structure(self): - """Test stream_likes_compliance request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.stream_client, "stream_likes_compliance") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/likes/compliance/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_likes_compliance: {e}") - - - def test_stream_likes_compliance_required_parameters(self): - """Test that stream_likes_compliance handles parameters correctly.""" - method = getattr(self.stream_client, "stream_likes_compliance") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_stream_likes_compliance_response_structure(self): - """Test stream_likes_compliance response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.stream_client, "stream_likes_compliance") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_firehose_ko_request_structure(self): - """Test stream_posts_firehose_ko request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.stream_client, "stream_posts_firehose_ko") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/firehose/stream/lang/ko" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose_ko: {e}") - - - def test_stream_posts_firehose_ko_required_parameters(self): - """Test that stream_posts_firehose_ko handles parameters correctly.""" - method = getattr(self.stream_client, "stream_posts_firehose_ko") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_firehose_ko_response_structure(self): - """Test stream_posts_firehose_ko response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.stream_client, "stream_posts_firehose_ko") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_users_compliance_request_structure(self): - """Test stream_users_compliance request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.stream_client, "stream_users_compliance") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/compliance/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_users_compliance: {e}") - - - def test_stream_users_compliance_required_parameters(self): - """Test that stream_users_compliance handles parameters correctly.""" - method = getattr(self.stream_client, "stream_users_compliance") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_users_compliance_response_structure(self): - """Test stream_users_compliance response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.stream_client, "stream_users_compliance") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_request_structure(self): - """Test stream_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.stream_client, "stream_posts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/search/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts: {e}") - - - def test_stream_posts_required_parameters(self): - """Test that stream_posts handles parameters correctly.""" - method = getattr(self.stream_client, "stream_posts") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_stream_posts_response_structure(self): - """Test stream_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.stream_client, "stream_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_labels_compliance_request_structure(self): - """Test stream_labels_compliance request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.stream_client, "stream_labels_compliance") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/label/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_labels_compliance: {e}") - - - def test_stream_labels_compliance_required_parameters(self): - """Test that stream_labels_compliance handles parameters correctly.""" - method = getattr(self.stream_client, "stream_labels_compliance") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_stream_labels_compliance_response_structure(self): - """Test stream_labels_compliance response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.stream_client, "stream_labels_compliance") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_compliance_request_structure(self): - """Test stream_posts_compliance request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.stream_client, "stream_posts_compliance") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/compliance/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_compliance: {e}") - - - def test_stream_posts_compliance_required_parameters(self): - """Test that stream_posts_compliance handles parameters correctly.""" - method = getattr(self.stream_client, "stream_posts_compliance") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_compliance_response_structure(self): - """Test stream_posts_compliance response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.stream_client, "stream_posts_compliance") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_sample_request_structure(self): - """Test stream_posts_sample request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.stream_client, "stream_posts_sample") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/sample/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_sample: {e}") - - - def test_stream_posts_sample_required_parameters(self): - """Test that stream_posts_sample handles parameters correctly.""" - method = getattr(self.stream_client, "stream_posts_sample") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_stream_posts_sample_response_structure(self): - """Test stream_posts_sample response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.stream_client, "stream_posts_sample") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_firehose_ja_request_structure(self): - """Test stream_posts_firehose_ja request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.stream_client, "stream_posts_firehose_ja") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/firehose/stream/lang/ja" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose_ja: {e}") - - - def test_stream_posts_firehose_ja_required_parameters(self): - """Test that stream_posts_firehose_ja handles parameters correctly.""" - method = getattr(self.stream_client, "stream_posts_firehose_ja") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_firehose_ja_response_structure(self): - """Test stream_posts_firehose_ja response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.stream_client, "stream_posts_firehose_ja") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_firehose_pt_request_structure(self): - """Test stream_posts_firehose_pt request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.stream_client, "stream_posts_firehose_pt") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/firehose/stream/lang/pt" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose_pt: {e}") - - - def test_stream_posts_firehose_pt_required_parameters(self): - """Test that stream_posts_firehose_pt handles parameters correctly.""" - method = getattr(self.stream_client, "stream_posts_firehose_pt") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_firehose_pt_response_structure(self): - """Test stream_posts_firehose_pt response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.stream_client, "stream_posts_firehose_pt") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_rules_request_structure(self): - """Test get_rules request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.stream_client, "get_rules") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/search/stream/rules" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_rules: {e}") - - - def test_get_rules_required_parameters(self): - """Test that get_rules handles parameters correctly.""" - method = getattr(self.stream_client, "get_rules") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_get_rules_response_structure(self): - """Test get_rules response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.stream_client, "get_rules") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_update_rules_request_structure(self): - """Test update_rules request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Import and create proper request model instance - from xdk.stream.models import UpdaterulesRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = UpdaterulesRequest() - # Call the method - try: - method = getattr(self.stream_client, "update_rules") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/search/stream/rules" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for update_rules: {e}") - - - def test_update_rules_required_parameters(self): - """Test that update_rules handles parameters correctly.""" - method = getattr(self.stream_client, "update_rules") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_update_rules_response_structure(self): - """Test update_rules response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Import and create proper request model instance - from xdk.stream.models import UpdaterulesRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = UpdaterulesRequest() - # Call method and verify response structure - method = getattr(self.stream_client, "update_rules") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/xdk/python/tests/stream/test_generic.py b/xdk/python/xdk/python/tests/stream/test_generic.py deleted file mode 100644 index 867e3771..00000000 --- a/xdk/python/xdk/python/tests/stream/test_generic.py +++ /dev/null @@ -1,122 +0,0 @@ -""" -Auto-generated generic tests for Stream client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.stream.client import StreamClient -from xdk import Client - - -class TestStreamGeneric: - """Generic tests for StreamClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.stream_client = getattr(self.client, "stream") - - - def test_client_exists(self): - """Test that StreamClient class exists and is importable.""" - assert StreamClient is not None - assert hasattr(StreamClient, "__name__") - assert StreamClient.__name__ == "StreamClient" - - - def test_client_initialization(self): - """Test that StreamClient can be initialized properly.""" - assert self.stream_client is not None - assert isinstance(self.stream_client, StreamClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(StreamClient) - if not name.startswith("_") and callable(getattr(StreamClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.stream_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "stream") - # Client should have standard Python object features - assert hasattr(self.stream_client, "__class__") - assert hasattr(self.stream_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.stream_client) - if not name.startswith("_") and callable(getattr(self.stream_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"StreamClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(StreamClient) - if not name.startswith("_") and callable(getattr(StreamClient, name)) - ] - for method_name in public_methods: - method = getattr(StreamClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/xdk/python/tests/stream/test_pagination.py b/xdk/python/xdk/python/tests/stream/test_pagination.py deleted file mode 100644 index e39385c4..00000000 --- a/xdk/python/xdk/python/tests/stream/test_pagination.py +++ /dev/null @@ -1,382 +0,0 @@ -""" -Auto-generated pagination tests for Stream client. - -This module contains tests that validate pagination functionality -using the Cursor class for methods that support pagination. - -Generated automatically - do not edit manually. -""" - -import pytest -from unittest.mock import Mock, patch -from xdk.stream.client import StreamClient -from xdk import Client, Cursor, cursor, PaginationError - - -class TestStreamPagination: - """Test pagination functionality for StreamClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.stream_client = getattr(self.client, "stream") - - - def test_get_rules_cursor_creation(self): - """Test that get_rules can be used with Cursor.""" - method = getattr(self.stream_client, "get_rules") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getRules should support pagination") - - - def test_get_rules_cursor_pages(self): - """Test pagination with pages() for get_rules.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.stream_client, "get_rules") - test_cursor = cursor(method, max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_rules_cursor_items(self): - """Test pagination with items() for get_rules.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.stream_client, "get_rules") - test_cursor = cursor(method, max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_rules_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_rules.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.stream_client, "get_rules") - # Test with max_results parameter - test_cursor = cursor(method, max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_pagination_edge_cases(self): - """Test pagination edge cases.""" - with patch.object(self.client, "session") as mock_session: - # Test empty response - empty_response = Mock() - empty_response.status_code = 200 - # Use null/None for data to handle both list and object response types - empty_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - empty_response.raise_for_status.return_value = None - mock_session.get.return_value = empty_response - # Pick first paginatable method for testing - method = getattr(self.stream_client, "get_rules") - test_cursor = cursor(method, max_results=10) - # Should handle empty responses gracefully - pages = list(test_cursor.pages(1)) - assert len(pages) == 1, "Should get one page even if empty" - items = list(test_cursor.items(10)) - assert len(items) == 0, "Should get no items from empty response" - - - def test_non_paginatable_method_raises_error(self): - """Test that non-paginatable methods raise PaginationError.""" - # Create a mock method that doesn't support pagination - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def test_cursor_class_functionality(self): - """Test basic Cursor class functionality.""" - # Test that Cursor can be imported and instantiated - from xdk.paginator import Cursor - assert Cursor is not None - # Test cursor factory function - from xdk.paginator import cursor as cursor_factory - assert cursor_factory is not None diff --git a/xdk/python/xdk/python/tests/stream/test_structure.py b/xdk/python/xdk/python/tests/stream/test_structure.py deleted file mode 100644 index 03c9b88d..00000000 --- a/xdk/python/xdk/python/tests/stream/test_structure.py +++ /dev/null @@ -1,908 +0,0 @@ -""" -Auto-generated structural tests for Stream client. - -This module contains tests that validate the structure and API surface -of the Stream client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.stream.client import StreamClient -from xdk import Client - - -class TestStreamStructure: - """Test the structure of StreamClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.stream_client = getattr(self.client, "stream") - - - def test_stream_likes_firehose_exists(self): - """Test that stream_likes_firehose method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "stream_likes_firehose", None) - assert ( - method is not None - ), f"Method stream_likes_firehose does not exist on StreamClient" - # Check method is callable - assert callable(method), f"stream_likes_firehose is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_likes_firehose should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_likes_firehose" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_likes_firehose_return_annotation(self): - """Test that stream_likes_firehose has proper return type annotation.""" - method = getattr(StreamClient, "stream_likes_firehose") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_likes_firehose should have return type annotation" - - - def test_stream_posts_sample10_exists(self): - """Test that stream_posts_sample10 method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "stream_posts_sample10", None) - assert ( - method is not None - ), f"Method stream_posts_sample10 does not exist on StreamClient" - # Check method is callable - assert callable(method), f"stream_posts_sample10 is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_sample10 should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_sample10" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_sample10_return_annotation(self): - """Test that stream_posts_sample10 has proper return type annotation.""" - method = getattr(StreamClient, "stream_posts_sample10") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_sample10 should have return type annotation" - - - def test_stream_likes_sample10_exists(self): - """Test that stream_likes_sample10 method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "stream_likes_sample10", None) - assert ( - method is not None - ), f"Method stream_likes_sample10 does not exist on StreamClient" - # Check method is callable - assert callable(method), f"stream_likes_sample10 is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_likes_sample10 should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_likes_sample10" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_likes_sample10_return_annotation(self): - """Test that stream_likes_sample10 has proper return type annotation.""" - method = getattr(StreamClient, "stream_likes_sample10") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_likes_sample10 should have return type annotation" - - - def test_stream_posts_firehose_exists(self): - """Test that stream_posts_firehose method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "stream_posts_firehose", None) - assert ( - method is not None - ), f"Method stream_posts_firehose does not exist on StreamClient" - # Check method is callable - assert callable(method), f"stream_posts_firehose is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_firehose should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_firehose_return_annotation(self): - """Test that stream_posts_firehose has proper return type annotation.""" - method = getattr(StreamClient, "stream_posts_firehose") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose should have return type annotation" - - - def test_get_rule_counts_exists(self): - """Test that get_rule_counts method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "get_rule_counts", None) - assert ( - method is not None - ), f"Method get_rule_counts does not exist on StreamClient" - # Check method is callable - assert callable(method), f"get_rule_counts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_rule_counts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_rule_counts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_rule_counts_return_annotation(self): - """Test that get_rule_counts has proper return type annotation.""" - method = getattr(StreamClient, "get_rule_counts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_rule_counts should have return type annotation" - - - def test_stream_posts_firehose_en_exists(self): - """Test that stream_posts_firehose_en method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "stream_posts_firehose_en", None) - assert ( - method is not None - ), f"Method stream_posts_firehose_en does not exist on StreamClient" - # Check method is callable - assert callable(method), f"stream_posts_firehose_en is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_firehose_en should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose_en" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_firehose_en_return_annotation(self): - """Test that stream_posts_firehose_en has proper return type annotation.""" - method = getattr(StreamClient, "stream_posts_firehose_en") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose_en should have return type annotation" - - - def test_stream_likes_compliance_exists(self): - """Test that stream_likes_compliance method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "stream_likes_compliance", None) - assert ( - method is not None - ), f"Method stream_likes_compliance does not exist on StreamClient" - # Check method is callable - assert callable(method), f"stream_likes_compliance is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_likes_compliance should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_likes_compliance" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_likes_compliance_return_annotation(self): - """Test that stream_likes_compliance has proper return type annotation.""" - method = getattr(StreamClient, "stream_likes_compliance") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_likes_compliance should have return type annotation" - - - def test_stream_posts_firehose_ko_exists(self): - """Test that stream_posts_firehose_ko method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "stream_posts_firehose_ko", None) - assert ( - method is not None - ), f"Method stream_posts_firehose_ko does not exist on StreamClient" - # Check method is callable - assert callable(method), f"stream_posts_firehose_ko is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_firehose_ko should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose_ko" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_firehose_ko_return_annotation(self): - """Test that stream_posts_firehose_ko has proper return type annotation.""" - method = getattr(StreamClient, "stream_posts_firehose_ko") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose_ko should have return type annotation" - - - def test_stream_users_compliance_exists(self): - """Test that stream_users_compliance method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "stream_users_compliance", None) - assert ( - method is not None - ), f"Method stream_users_compliance does not exist on StreamClient" - # Check method is callable - assert callable(method), f"stream_users_compliance is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_users_compliance should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_users_compliance" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_users_compliance_return_annotation(self): - """Test that stream_users_compliance has proper return type annotation.""" - method = getattr(StreamClient, "stream_users_compliance") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_users_compliance should have return type annotation" - - - def test_stream_posts_exists(self): - """Test that stream_posts method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "stream_posts", None) - assert method is not None, f"Method stream_posts does not exist on StreamClient" - # Check method is callable - assert callable(method), f"stream_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"stream_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_return_annotation(self): - """Test that stream_posts has proper return type annotation.""" - method = getattr(StreamClient, "stream_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts should have return type annotation" - - - def test_stream_labels_compliance_exists(self): - """Test that stream_labels_compliance method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "stream_labels_compliance", None) - assert ( - method is not None - ), f"Method stream_labels_compliance does not exist on StreamClient" - # Check method is callable - assert callable(method), f"stream_labels_compliance is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_labels_compliance should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_labels_compliance" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_labels_compliance_return_annotation(self): - """Test that stream_labels_compliance has proper return type annotation.""" - method = getattr(StreamClient, "stream_labels_compliance") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_labels_compliance should have return type annotation" - - - def test_stream_posts_compliance_exists(self): - """Test that stream_posts_compliance method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "stream_posts_compliance", None) - assert ( - method is not None - ), f"Method stream_posts_compliance does not exist on StreamClient" - # Check method is callable - assert callable(method), f"stream_posts_compliance is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_compliance should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_compliance" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_compliance_return_annotation(self): - """Test that stream_posts_compliance has proper return type annotation.""" - method = getattr(StreamClient, "stream_posts_compliance") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_compliance should have return type annotation" - - - def test_stream_posts_sample_exists(self): - """Test that stream_posts_sample method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "stream_posts_sample", None) - assert ( - method is not None - ), f"Method stream_posts_sample does not exist on StreamClient" - # Check method is callable - assert callable(method), f"stream_posts_sample is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_sample should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_sample" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_sample_return_annotation(self): - """Test that stream_posts_sample has proper return type annotation.""" - method = getattr(StreamClient, "stream_posts_sample") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_sample should have return type annotation" - - - def test_stream_posts_firehose_ja_exists(self): - """Test that stream_posts_firehose_ja method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "stream_posts_firehose_ja", None) - assert ( - method is not None - ), f"Method stream_posts_firehose_ja does not exist on StreamClient" - # Check method is callable - assert callable(method), f"stream_posts_firehose_ja is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_firehose_ja should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose_ja" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_firehose_ja_return_annotation(self): - """Test that stream_posts_firehose_ja has proper return type annotation.""" - method = getattr(StreamClient, "stream_posts_firehose_ja") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose_ja should have return type annotation" - - - def test_stream_posts_firehose_pt_exists(self): - """Test that stream_posts_firehose_pt method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "stream_posts_firehose_pt", None) - assert ( - method is not None - ), f"Method stream_posts_firehose_pt does not exist on StreamClient" - # Check method is callable - assert callable(method), f"stream_posts_firehose_pt is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_firehose_pt should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose_pt" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_firehose_pt_return_annotation(self): - """Test that stream_posts_firehose_pt has proper return type annotation.""" - method = getattr(StreamClient, "stream_posts_firehose_pt") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose_pt should have return type annotation" - - - def test_get_rules_exists(self): - """Test that get_rules method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "get_rules", None) - assert method is not None, f"Method get_rules does not exist on StreamClient" - # Check method is callable - assert callable(method), f"get_rules is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"get_rules should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_rules" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "ids", - "max_results", - "pagination_token", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_rules_return_annotation(self): - """Test that get_rules has proper return type annotation.""" - method = getattr(StreamClient, "get_rules") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_rules should have return type annotation" - - - def test_get_rules_pagination_params(self): - """Test that get_rules has pagination parameters.""" - method = getattr(StreamClient, "get_rules") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_rules should have pagination parameters" - - - def test_update_rules_exists(self): - """Test that update_rules method exists with correct signature.""" - # Check method exists - method = getattr(StreamClient, "update_rules", None) - assert method is not None, f"Method update_rules does not exist on StreamClient" - # Check method is callable - assert callable(method), f"update_rules is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"update_rules should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from update_rules" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "dry_run", - "delete_all", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_update_rules_return_annotation(self): - """Test that update_rules has proper return type annotation.""" - method = getattr(StreamClient, "update_rules") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method update_rules should have return type annotation" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "stream_likes_firehose", - "stream_posts_sample10", - "stream_likes_sample10", - "stream_posts_firehose", - "get_rule_counts", - "stream_posts_firehose_en", - "stream_likes_compliance", - "stream_posts_firehose_ko", - "stream_users_compliance", - "stream_posts", - "stream_labels_compliance", - "stream_posts_compliance", - "stream_posts_sample", - "stream_posts_firehose_ja", - "stream_posts_firehose_pt", - "get_rules", - "update_rules", - ] - for expected_method in expected_methods: - assert hasattr( - StreamClient, expected_method - ), f"Expected method '{expected_method}' not found on StreamClient" - assert callable( - getattr(StreamClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/xdk/python/tests/trends/__init__.py b/xdk/python/xdk/python/tests/trends/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/trends/test_contracts.py b/xdk/python/xdk/python/tests/trends/test_contracts.py deleted file mode 100644 index adc6a2b2..00000000 --- a/xdk/python/xdk/python/tests/trends/test_contracts.py +++ /dev/null @@ -1,194 +0,0 @@ -""" -Auto-generated contract tests for Trends client. - -This module contains tests that validate the request/response contracts -of the Trends client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.trends.client import TrendsClient -from xdk import Client - - -class TestTrendsContracts: - """Test the API contracts of TrendsClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.trends_client = getattr(self.client, "trends") - - - def test_get_users_personalized_trends_request_structure(self): - """Test get_users_personalized_trends request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.trends_client, "get_users_personalized_trends") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/personalized_trends" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail( - f"Contract test failed for get_users_personalized_trends: {e}" - ) - - - def test_get_users_personalized_trends_required_parameters(self): - """Test that get_users_personalized_trends handles parameters correctly.""" - method = getattr(self.trends_client, "get_users_personalized_trends") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_get_users_personalized_trends_response_structure(self): - """Test get_users_personalized_trends response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.trends_client, "get_users_personalized_trends") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_trends_by_woeid_request_structure(self): - """Test get_trends_by_woeid request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["woeid"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.trends_client, "get_trends_by_woeid") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/trends/by/woeid/{woeid}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_trends_by_woeid: {e}") - - - def test_get_trends_by_woeid_required_parameters(self): - """Test that get_trends_by_woeid handles parameters correctly.""" - method = getattr(self.trends_client, "get_trends_by_woeid") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_trends_by_woeid_response_structure(self): - """Test get_trends_by_woeid response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["woeid"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.trends_client, "get_trends_by_woeid") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/xdk/python/tests/trends/test_generic.py b/xdk/python/xdk/python/tests/trends/test_generic.py deleted file mode 100644 index bbbb1a37..00000000 --- a/xdk/python/xdk/python/tests/trends/test_generic.py +++ /dev/null @@ -1,122 +0,0 @@ -""" -Auto-generated generic tests for Trends client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.trends.client import TrendsClient -from xdk import Client - - -class TestTrendsGeneric: - """Generic tests for TrendsClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.trends_client = getattr(self.client, "trends") - - - def test_client_exists(self): - """Test that TrendsClient class exists and is importable.""" - assert TrendsClient is not None - assert hasattr(TrendsClient, "__name__") - assert TrendsClient.__name__ == "TrendsClient" - - - def test_client_initialization(self): - """Test that TrendsClient can be initialized properly.""" - assert self.trends_client is not None - assert isinstance(self.trends_client, TrendsClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(TrendsClient) - if not name.startswith("_") and callable(getattr(TrendsClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.trends_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "trends") - # Client should have standard Python object features - assert hasattr(self.trends_client, "__class__") - assert hasattr(self.trends_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.trends_client) - if not name.startswith("_") and callable(getattr(self.trends_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"TrendsClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(TrendsClient) - if not name.startswith("_") and callable(getattr(TrendsClient, name)) - ] - for method_name in public_methods: - method = getattr(TrendsClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/xdk/python/tests/trends/test_structure.py b/xdk/python/xdk/python/tests/trends/test_structure.py deleted file mode 100644 index 0078ff19..00000000 --- a/xdk/python/xdk/python/tests/trends/test_structure.py +++ /dev/null @@ -1,134 +0,0 @@ -""" -Auto-generated structural tests for Trends client. - -This module contains tests that validate the structure and API surface -of the Trends client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.trends.client import TrendsClient -from xdk import Client - - -class TestTrendsStructure: - """Test the structure of TrendsClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.trends_client = getattr(self.client, "trends") - - - def test_get_users_personalized_trends_exists(self): - """Test that get_users_personalized_trends method exists with correct signature.""" - # Check method exists - method = getattr(TrendsClient, "get_users_personalized_trends", None) - assert ( - method is not None - ), f"Method get_users_personalized_trends does not exist on TrendsClient" - # Check method is callable - assert callable(method), f"get_users_personalized_trends is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_personalized_trends should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_users_personalized_trends" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_users_personalized_trends_return_annotation(self): - """Test that get_users_personalized_trends has proper return type annotation.""" - method = getattr(TrendsClient, "get_users_personalized_trends") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_personalized_trends should have return type annotation" - - - def test_get_trends_by_woeid_exists(self): - """Test that get_trends_by_woeid method exists with correct signature.""" - # Check method exists - method = getattr(TrendsClient, "get_trends_by_woeid", None) - assert ( - method is not None - ), f"Method get_trends_by_woeid does not exist on TrendsClient" - # Check method is callable - assert callable(method), f"get_trends_by_woeid is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_trends_by_woeid should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "woeid", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_trends_by_woeid" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_trends", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_trends_by_woeid_return_annotation(self): - """Test that get_trends_by_woeid has proper return type annotation.""" - method = getattr(TrendsClient, "get_trends_by_woeid") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_trends_by_woeid should have return type annotation" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "get_users_personalized_trends", - "get_trends_by_woeid", - ] - for expected_method in expected_methods: - assert hasattr( - TrendsClient, expected_method - ), f"Expected method '{expected_method}' not found on TrendsClient" - assert callable( - getattr(TrendsClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/xdk/python/tests/tweets/__init__.py b/xdk/python/xdk/python/tests/tweets/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/tweets/test_contracts.py b/xdk/python/xdk/python/tests/tweets/test_contracts.py deleted file mode 100644 index 294bc74c..00000000 --- a/xdk/python/xdk/python/tests/tweets/test_contracts.py +++ /dev/null @@ -1,3134 +0,0 @@ -""" -Auto-generated contract tests for Tweets client. - -This module contains tests that validate the request/response contracts -of the Tweets client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.tweets.client import TweetsClient -from xdk import Client - - -class TestTweetsContracts: - """Test the API contracts of TweetsClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.tweets_client = getattr(self.client, "tweets") - - - def test_stream_posts_sample10_request_structure(self): - """Test stream_posts_sample10 request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "stream_posts_sample10") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/sample10/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_sample10: {e}") - - - def test_stream_posts_sample10_required_parameters(self): - """Test that stream_posts_sample10 handles parameters correctly.""" - method = getattr(self.tweets_client, "stream_posts_sample10") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_sample10_response_structure(self): - """Test stream_posts_sample10 response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "stream_posts_sample10") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_spaces_posts_request_structure(self): - """Test get_spaces_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_id" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_spaces_posts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/spaces/{id}/tweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_spaces_posts: {e}") - - - def test_get_spaces_posts_required_parameters(self): - """Test that get_spaces_posts handles parameters correctly.""" - method = getattr(self.tweets_client, "get_spaces_posts") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_spaces_posts_response_structure(self): - """Test get_spaces_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_spaces_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_lists_posts_request_structure(self): - """Test get_lists_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_lists_posts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/lists/{id}/tweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_lists_posts: {e}") - - - def test_get_lists_posts_required_parameters(self): - """Test that get_lists_posts handles parameters correctly.""" - method = getattr(self.tweets_client, "get_lists_posts") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_lists_posts_response_structure(self): - """Test get_lists_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_lists_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_posts_counts_recent_request_structure(self): - """Test get_posts_counts_recent request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["query"] = "test_query" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_posts_counts_recent") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/counts/recent" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_posts_counts_recent: {e}") - - - def test_get_posts_counts_recent_required_parameters(self): - """Test that get_posts_counts_recent handles parameters correctly.""" - method = getattr(self.tweets_client, "get_posts_counts_recent") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_posts_counts_recent_response_structure(self): - """Test get_posts_counts_recent response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["query"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_posts_counts_recent") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_search_posts_recent_request_structure(self): - """Test search_posts_recent request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["query"] = "test_query" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "search_posts_recent") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/search/recent" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for search_posts_recent: {e}") - - - def test_search_posts_recent_required_parameters(self): - """Test that search_posts_recent handles parameters correctly.""" - method = getattr(self.tweets_client, "search_posts_recent") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_search_posts_recent_response_structure(self): - """Test search_posts_recent response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["query"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "search_posts_recent") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_posts_counts_all_request_structure(self): - """Test get_posts_counts_all request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["query"] = "test_query" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_posts_counts_all") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/counts/all" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_posts_counts_all: {e}") - - - def test_get_posts_counts_all_required_parameters(self): - """Test that get_posts_counts_all handles parameters correctly.""" - method = getattr(self.tweets_client, "get_posts_counts_all") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_posts_counts_all_response_structure(self): - """Test get_posts_counts_all response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["query"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_posts_counts_all") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_firehose_request_structure(self): - """Test stream_posts_firehose request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "stream_posts_firehose") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/firehose/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose: {e}") - - - def test_stream_posts_firehose_required_parameters(self): - """Test that stream_posts_firehose handles parameters correctly.""" - method = getattr(self.tweets_client, "stream_posts_firehose") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_firehose_response_structure(self): - """Test stream_posts_firehose response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "stream_posts_firehose") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_rule_counts_request_structure(self): - """Test get_rule_counts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_rule_counts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/search/stream/rules/counts" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_rule_counts: {e}") - - - def test_get_rule_counts_required_parameters(self): - """Test that get_rule_counts handles parameters correctly.""" - method = getattr(self.tweets_client, "get_rule_counts") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_get_rule_counts_response_structure(self): - """Test get_rule_counts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_rule_counts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_firehose_en_request_structure(self): - """Test stream_posts_firehose_en request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "stream_posts_firehose_en") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/firehose/stream/lang/en" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose_en: {e}") - - - def test_stream_posts_firehose_en_required_parameters(self): - """Test that stream_posts_firehose_en handles parameters correctly.""" - method = getattr(self.tweets_client, "stream_posts_firehose_en") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_firehose_en_response_structure(self): - """Test stream_posts_firehose_en response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "stream_posts_firehose_en") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_like_post_request_structure(self): - """Test like_post request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import LikepostRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = LikepostRequest() - # Call the method - try: - method = getattr(self.tweets_client, "like_post") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/likes" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for like_post: {e}") - - - def test_like_post_required_parameters(self): - """Test that like_post handles parameters correctly.""" - method = getattr(self.tweets_client, "like_post") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_like_post_response_structure(self): - """Test like_post response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import LikepostRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = LikepostRequest() - # Call method and verify response structure - method = getattr(self.tweets_client, "like_post") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_posts_analytics_request_structure(self): - """Test get_posts_analytics request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["ids"] = ["test_item"] - kwargs["end_time"] = "test_end_time" - kwargs["start_time"] = "test_start_time" - kwargs["granularity"] = "test_granularity" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_posts_analytics") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/analytics" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_posts_analytics: {e}") - - - def test_get_posts_analytics_required_parameters(self): - """Test that get_posts_analytics handles parameters correctly.""" - method = getattr(self.tweets_client, "get_posts_analytics") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_posts_analytics_response_structure(self): - """Test get_posts_analytics response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["ids"] = ["test"] - kwargs["end_time"] = "test_value" - kwargs["start_time"] = "test_value" - kwargs["granularity"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_posts_analytics") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_firehose_ko_request_structure(self): - """Test stream_posts_firehose_ko request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "stream_posts_firehose_ko") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/firehose/stream/lang/ko" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose_ko: {e}") - - - def test_stream_posts_firehose_ko_required_parameters(self): - """Test that stream_posts_firehose_ko handles parameters correctly.""" - method = getattr(self.tweets_client, "stream_posts_firehose_ko") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_firehose_ko_response_structure(self): - """Test stream_posts_firehose_ko response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "stream_posts_firehose_ko") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_request_structure(self): - """Test stream_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "stream_posts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/search/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts: {e}") - - - def test_stream_posts_required_parameters(self): - """Test that stream_posts handles parameters correctly.""" - method = getattr(self.tweets_client, "stream_posts") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_stream_posts_response_structure(self): - """Test stream_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "stream_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_posts_quoted_posts_request_structure(self): - """Test get_posts_quoted_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_posts_quoted_posts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/{id}/quote_tweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_posts_quoted_posts: {e}") - - - def test_get_posts_quoted_posts_required_parameters(self): - """Test that get_posts_quoted_posts handles parameters correctly.""" - method = getattr(self.tweets_client, "get_posts_quoted_posts") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_posts_quoted_posts_response_structure(self): - """Test get_posts_quoted_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_posts_quoted_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_users_mentions_request_structure(self): - """Test get_users_mentions request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_users_mentions") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/mentions" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_users_mentions: {e}") - - - def test_get_users_mentions_required_parameters(self): - """Test that get_users_mentions handles parameters correctly.""" - method = getattr(self.tweets_client, "get_users_mentions") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_users_mentions_response_structure(self): - """Test get_users_mentions response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_users_mentions") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_unlike_post_request_structure(self): - """Test unlike_post request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - kwargs["tweet_id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "unlike_post") - result = method(**kwargs) - # Verify the request was made - mock_session.delete.assert_called_once() - # Verify request structure - call_args = mock_session.delete.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/likes/{tweet_id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for unlike_post: {e}") - - - def test_unlike_post_required_parameters(self): - """Test that unlike_post handles parameters correctly.""" - method = getattr(self.tweets_client, "unlike_post") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_unlike_post_response_structure(self): - """Test unlike_post response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - kwargs["tweet_id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "unlike_post") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_posts_by_id_request_structure(self): - """Test get_posts_by_id request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_posts_by_id") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/{id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_posts_by_id: {e}") - - - def test_get_posts_by_id_required_parameters(self): - """Test that get_posts_by_id handles parameters correctly.""" - method = getattr(self.tweets_client, "get_posts_by_id") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_posts_by_id_response_structure(self): - """Test get_posts_by_id response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_posts_by_id") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_delete_posts_request_structure(self): - """Test delete_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "delete_posts") - result = method(**kwargs) - # Verify the request was made - mock_session.delete.assert_called_once() - # Verify request structure - call_args = mock_session.delete.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/{id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for delete_posts: {e}") - - - def test_delete_posts_required_parameters(self): - """Test that delete_posts handles parameters correctly.""" - method = getattr(self.tweets_client, "delete_posts") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_delete_posts_response_structure(self): - """Test delete_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "delete_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_search_posts_all_request_structure(self): - """Test search_posts_all request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["query"] = "test_query" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "search_posts_all") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/search/all" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for search_posts_all: {e}") - - - def test_search_posts_all_required_parameters(self): - """Test that search_posts_all handles parameters correctly.""" - method = getattr(self.tweets_client, "search_posts_all") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_search_posts_all_response_structure(self): - """Test search_posts_all response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["query"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "search_posts_all") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_hide_posts_reply_request_structure(self): - """Test hide_posts_reply request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.put.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["tweet_id"] = "test_value" - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import HidepostsreplyRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = HidepostsreplyRequest() - # Call the method - try: - method = getattr(self.tweets_client, "hide_posts_reply") - result = method(**kwargs) - # Verify the request was made - mock_session.put.assert_called_once() - # Verify request structure - call_args = mock_session.put.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/{tweet_id}/hidden" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for hide_posts_reply: {e}") - - - def test_hide_posts_reply_required_parameters(self): - """Test that hide_posts_reply handles parameters correctly.""" - method = getattr(self.tweets_client, "hide_posts_reply") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.put.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_hide_posts_reply_response_structure(self): - """Test hide_posts_reply response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.put.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["tweet_id"] = "test" - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import HidepostsreplyRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = HidepostsreplyRequest() - # Call method and verify response structure - method = getattr(self.tweets_client, "hide_posts_reply") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_sample_request_structure(self): - """Test stream_posts_sample request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "stream_posts_sample") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/sample/stream" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_sample: {e}") - - - def test_stream_posts_sample_required_parameters(self): - """Test that stream_posts_sample handles parameters correctly.""" - method = getattr(self.tweets_client, "stream_posts_sample") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_stream_posts_sample_response_structure(self): - """Test stream_posts_sample response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "stream_posts_sample") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_users_timeline_request_structure(self): - """Test get_users_timeline request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_users_timeline") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/timelines/reverse_chronological" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_users_timeline: {e}") - - - def test_get_users_timeline_required_parameters(self): - """Test that get_users_timeline handles parameters correctly.""" - method = getattr(self.tweets_client, "get_users_timeline") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_users_timeline_response_structure(self): - """Test get_users_timeline response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_users_timeline") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_users_posts_request_structure(self): - """Test get_users_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_users_posts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/tweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_users_posts: {e}") - - - def test_get_users_posts_required_parameters(self): - """Test that get_users_posts handles parameters correctly.""" - method = getattr(self.tweets_client, "get_users_posts") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_users_posts_response_structure(self): - """Test get_users_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_users_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_spaces_buyers_request_structure(self): - """Test get_spaces_buyers request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_id" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_spaces_buyers") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/spaces/{id}/buyers" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_spaces_buyers: {e}") - - - def test_get_spaces_buyers_required_parameters(self): - """Test that get_spaces_buyers handles parameters correctly.""" - method = getattr(self.tweets_client, "get_spaces_buyers") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_spaces_buyers_response_structure(self): - """Test get_spaces_buyers response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test_value" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_spaces_buyers") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_repost_post_request_structure(self): - """Test repost_post request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import RepostpostRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = RepostpostRequest() - # Call the method - try: - method = getattr(self.tweets_client, "repost_post") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/retweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for repost_post: {e}") - - - def test_repost_post_required_parameters(self): - """Test that repost_post handles parameters correctly.""" - method = getattr(self.tweets_client, "repost_post") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_repost_post_response_structure(self): - """Test repost_post response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import RepostpostRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = RepostpostRequest() - # Call method and verify response structure - method = getattr(self.tweets_client, "repost_post") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_insights28_hr_request_structure(self): - """Test get_insights28_hr request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["tweet_ids"] = ["test_item"] - kwargs["granularity"] = "test_granularity" - kwargs["requested_metrics"] = ["test_item"] - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_insights28_hr") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/insights/28hr" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_insights28_hr: {e}") - - - def test_get_insights28_hr_required_parameters(self): - """Test that get_insights28_hr handles parameters correctly.""" - method = getattr(self.tweets_client, "get_insights28_hr") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_insights28_hr_response_structure(self): - """Test get_insights28_hr response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["tweet_ids"] = ["test"] - kwargs["granularity"] = "test_value" - kwargs["requested_metrics"] = ["test"] - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_insights28_hr") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_posts_by_ids_request_structure(self): - """Test get_posts_by_ids request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["ids"] = ["test_item"] - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_posts_by_ids") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_posts_by_ids: {e}") - - - def test_get_posts_by_ids_required_parameters(self): - """Test that get_posts_by_ids handles parameters correctly.""" - method = getattr(self.tweets_client, "get_posts_by_ids") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_posts_by_ids_response_structure(self): - """Test get_posts_by_ids response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["ids"] = ["test"] - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_posts_by_ids") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_create_posts_request_structure(self): - """Test create_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import CreatepostsRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatepostsRequest() - # Call the method - try: - method = getattr(self.tweets_client, "create_posts") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for create_posts: {e}") - - - def test_create_posts_required_parameters(self): - """Test that create_posts handles parameters correctly.""" - method = getattr(self.tweets_client, "create_posts") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_create_posts_response_structure(self): - """Test create_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import CreatepostsRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatepostsRequest() - # Call method and verify response structure - method = getattr(self.tweets_client, "create_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_users_liked_posts_request_structure(self): - """Test get_users_liked_posts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_users_liked_posts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/liked_tweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_users_liked_posts: {e}") - - - def test_get_users_liked_posts_required_parameters(self): - """Test that get_users_liked_posts handles parameters correctly.""" - method = getattr(self.tweets_client, "get_users_liked_posts") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_users_liked_posts_response_structure(self): - """Test get_users_liked_posts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_users_liked_posts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_insights_historical_request_structure(self): - """Test get_insights_historical request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["tweet_ids"] = ["test_item"] - kwargs["end_time"] = "test_end_time" - kwargs["start_time"] = "test_start_time" - kwargs["granularity"] = "test_granularity" - kwargs["requested_metrics"] = ["test_item"] - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_insights_historical") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/insights/historical" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_insights_historical: {e}") - - - def test_get_insights_historical_required_parameters(self): - """Test that get_insights_historical handles parameters correctly.""" - method = getattr(self.tweets_client, "get_insights_historical") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_insights_historical_response_structure(self): - """Test get_insights_historical response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["tweet_ids"] = ["test"] - kwargs["end_time"] = "test_value" - kwargs["start_time"] = "test_value" - kwargs["granularity"] = "test_value" - kwargs["requested_metrics"] = ["test"] - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_insights_historical") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_firehose_ja_request_structure(self): - """Test stream_posts_firehose_ja request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "stream_posts_firehose_ja") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/firehose/stream/lang/ja" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose_ja: {e}") - - - def test_stream_posts_firehose_ja_required_parameters(self): - """Test that stream_posts_firehose_ja handles parameters correctly.""" - method = getattr(self.tweets_client, "stream_posts_firehose_ja") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_firehose_ja_response_structure(self): - """Test stream_posts_firehose_ja response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "stream_posts_firehose_ja") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_stream_posts_firehose_pt_request_structure(self): - """Test stream_posts_firehose_pt request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["partition"] = 42 - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "stream_posts_firehose_pt") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/firehose/stream/lang/pt" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for stream_posts_firehose_pt: {e}") - - - def test_stream_posts_firehose_pt_required_parameters(self): - """Test that stream_posts_firehose_pt handles parameters correctly.""" - method = getattr(self.tweets_client, "stream_posts_firehose_pt") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_stream_posts_firehose_pt_response_structure(self): - """Test stream_posts_firehose_pt response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["partition"] = 1 - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "stream_posts_firehose_pt") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_unrepost_post_request_structure(self): - """Test unrepost_post request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - kwargs["source_tweet_id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "unrepost_post") - result = method(**kwargs) - # Verify the request was made - mock_session.delete.assert_called_once() - # Verify request structure - call_args = mock_session.delete.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/users/{id}/retweets/{source_tweet_id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for unrepost_post: {e}") - - - def test_unrepost_post_required_parameters(self): - """Test that unrepost_post handles parameters correctly.""" - method = getattr(self.tweets_client, "unrepost_post") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_unrepost_post_response_structure(self): - """Test unrepost_post response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - kwargs["source_tweet_id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "unrepost_post") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_posts_reposts_request_structure(self): - """Test get_posts_reposts request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_posts_reposts") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/{id}/retweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_posts_reposts: {e}") - - - def test_get_posts_reposts_required_parameters(self): - """Test that get_posts_reposts handles parameters correctly.""" - method = getattr(self.tweets_client, "get_posts_reposts") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.get.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_get_posts_reposts_response_structure(self): - """Test get_posts_reposts response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_posts_reposts") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_rules_request_structure(self): - """Test get_rules request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.tweets_client, "get_rules") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/search/stream/rules" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_rules: {e}") - - - def test_get_rules_required_parameters(self): - """Test that get_rules handles parameters correctly.""" - method = getattr(self.tweets_client, "get_rules") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_get_rules_response_structure(self): - """Test get_rules response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.tweets_client, "get_rules") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_update_rules_request_structure(self): - """Test update_rules request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import UpdaterulesRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = UpdaterulesRequest() - # Call the method - try: - method = getattr(self.tweets_client, "update_rules") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/tweets/search/stream/rules" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for update_rules: {e}") - - - def test_update_rules_required_parameters(self): - """Test that update_rules handles parameters correctly.""" - method = getattr(self.tweets_client, "update_rules") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_update_rules_response_structure(self): - """Test update_rules response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Import and create proper request model instance - from xdk.tweets.models import UpdaterulesRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = UpdaterulesRequest() - # Call method and verify response structure - method = getattr(self.tweets_client, "update_rules") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/xdk/python/tests/tweets/test_generic.py b/xdk/python/xdk/python/tests/tweets/test_generic.py deleted file mode 100644 index 281263ab..00000000 --- a/xdk/python/xdk/python/tests/tweets/test_generic.py +++ /dev/null @@ -1,122 +0,0 @@ -""" -Auto-generated generic tests for Tweets client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.tweets.client import TweetsClient -from xdk import Client - - -class TestTweetsGeneric: - """Generic tests for TweetsClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.tweets_client = getattr(self.client, "tweets") - - - def test_client_exists(self): - """Test that TweetsClient class exists and is importable.""" - assert TweetsClient is not None - assert hasattr(TweetsClient, "__name__") - assert TweetsClient.__name__ == "TweetsClient" - - - def test_client_initialization(self): - """Test that TweetsClient can be initialized properly.""" - assert self.tweets_client is not None - assert isinstance(self.tweets_client, TweetsClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(TweetsClient) - if not name.startswith("_") and callable(getattr(TweetsClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.tweets_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "tweets") - # Client should have standard Python object features - assert hasattr(self.tweets_client, "__class__") - assert hasattr(self.tweets_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.tweets_client) - if not name.startswith("_") and callable(getattr(self.tweets_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"TweetsClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(TweetsClient) - if not name.startswith("_") and callable(getattr(TweetsClient, name)) - ] - for method_name in public_methods: - method = getattr(TweetsClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/xdk/python/tests/tweets/test_pagination.py b/xdk/python/xdk/python/tests/tweets/test_pagination.py deleted file mode 100644 index af6f621c..00000000 --- a/xdk/python/xdk/python/tests/tweets/test_pagination.py +++ /dev/null @@ -1,1832 +0,0 @@ -""" -Auto-generated pagination tests for Tweets client. - -This module contains tests that validate pagination functionality -using the Cursor class for methods that support pagination. - -Generated automatically - do not edit manually. -""" - -import pytest -from unittest.mock import Mock, patch -from xdk.tweets.client import TweetsClient -from xdk import Client, Cursor, cursor, PaginationError - - -class TestTweetsPagination: - """Test pagination functionality for TweetsClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.tweets_client = getattr(self.client, "tweets") - - - def test_get_lists_posts_cursor_creation(self): - """Test that get_lists_posts can be used with Cursor.""" - method = getattr(self.tweets_client, "get_lists_posts") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getListsPosts should support pagination") - - - def test_get_lists_posts_cursor_pages(self): - """Test pagination with pages() for get_lists_posts.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "get_lists_posts") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_lists_posts_cursor_items(self): - """Test pagination with items() for get_lists_posts.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "get_lists_posts") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_lists_posts_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_lists_posts.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "get_lists_posts") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_search_posts_recent_cursor_creation(self): - """Test that search_posts_recent can be used with Cursor.""" - method = getattr(self.tweets_client, "search_posts_recent") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_query", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method searchPostsRecent should support pagination") - - - def test_search_posts_recent_cursor_pages(self): - """Test pagination with pages() for search_posts_recent.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "search_posts_recent") - test_cursor = cursor(method, "test_query", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_search_posts_recent_cursor_items(self): - """Test pagination with items() for search_posts_recent.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "search_posts_recent") - test_cursor = cursor(method, "test_query", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_search_posts_recent_pagination_parameters(self): - """Test that pagination parameters are handled correctly for search_posts_recent.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "search_posts_recent") - # Test with max_results parameter - test_cursor = cursor(method, "test_query", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_query", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_posts_quoted_posts_cursor_creation(self): - """Test that get_posts_quoted_posts can be used with Cursor.""" - method = getattr(self.tweets_client, "get_posts_quoted_posts") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getPostsQuotedPosts should support pagination") - - - def test_get_posts_quoted_posts_cursor_pages(self): - """Test pagination with pages() for get_posts_quoted_posts.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "get_posts_quoted_posts") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_posts_quoted_posts_cursor_items(self): - """Test pagination with items() for get_posts_quoted_posts.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "get_posts_quoted_posts") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_posts_quoted_posts_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_posts_quoted_posts.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "get_posts_quoted_posts") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_users_mentions_cursor_creation(self): - """Test that get_users_mentions can be used with Cursor.""" - method = getattr(self.tweets_client, "get_users_mentions") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersMentions should support pagination") - - - def test_get_users_mentions_cursor_pages(self): - """Test pagination with pages() for get_users_mentions.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "get_users_mentions") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_mentions_cursor_items(self): - """Test pagination with items() for get_users_mentions.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "get_users_mentions") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_mentions_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_mentions.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "get_users_mentions") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_search_posts_all_cursor_creation(self): - """Test that search_posts_all can be used with Cursor.""" - method = getattr(self.tweets_client, "search_posts_all") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_query", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method searchPostsAll should support pagination") - - - def test_search_posts_all_cursor_pages(self): - """Test pagination with pages() for search_posts_all.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "search_posts_all") - test_cursor = cursor(method, "test_query", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_search_posts_all_cursor_items(self): - """Test pagination with items() for search_posts_all.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "search_posts_all") - test_cursor = cursor(method, "test_query", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_search_posts_all_pagination_parameters(self): - """Test that pagination parameters are handled correctly for search_posts_all.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "search_posts_all") - # Test with max_results parameter - test_cursor = cursor(method, "test_query", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_query", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_users_timeline_cursor_creation(self): - """Test that get_users_timeline can be used with Cursor.""" - method = getattr(self.tweets_client, "get_users_timeline") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersTimeline should support pagination") - - - def test_get_users_timeline_cursor_pages(self): - """Test pagination with pages() for get_users_timeline.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "get_users_timeline") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_timeline_cursor_items(self): - """Test pagination with items() for get_users_timeline.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "get_users_timeline") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_timeline_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_timeline.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "get_users_timeline") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_users_posts_cursor_creation(self): - """Test that get_users_posts can be used with Cursor.""" - method = getattr(self.tweets_client, "get_users_posts") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersPosts should support pagination") - - - def test_get_users_posts_cursor_pages(self): - """Test pagination with pages() for get_users_posts.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "get_users_posts") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_posts_cursor_items(self): - """Test pagination with items() for get_users_posts.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "get_users_posts") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_posts_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_posts.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "get_users_posts") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_spaces_buyers_cursor_creation(self): - """Test that get_spaces_buyers can be used with Cursor.""" - method = getattr(self.tweets_client, "get_spaces_buyers") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getSpacesBuyers should support pagination") - - - def test_get_spaces_buyers_cursor_pages(self): - """Test pagination with pages() for get_spaces_buyers.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "get_spaces_buyers") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_spaces_buyers_cursor_items(self): - """Test pagination with items() for get_spaces_buyers.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "get_spaces_buyers") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_spaces_buyers_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_spaces_buyers.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "get_spaces_buyers") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_users_liked_posts_cursor_creation(self): - """Test that get_users_liked_posts can be used with Cursor.""" - method = getattr(self.tweets_client, "get_users_liked_posts") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersLikedPosts should support pagination") - - - def test_get_users_liked_posts_cursor_pages(self): - """Test pagination with pages() for get_users_liked_posts.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "get_users_liked_posts") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_liked_posts_cursor_items(self): - """Test pagination with items() for get_users_liked_posts.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "get_users_liked_posts") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_liked_posts_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_liked_posts.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "get_users_liked_posts") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_posts_reposts_cursor_creation(self): - """Test that get_posts_reposts can be used with Cursor.""" - method = getattr(self.tweets_client, "get_posts_reposts") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getPostsReposts should support pagination") - - - def test_get_posts_reposts_cursor_pages(self): - """Test pagination with pages() for get_posts_reposts.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "get_posts_reposts") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_posts_reposts_cursor_items(self): - """Test pagination with items() for get_posts_reposts.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "get_posts_reposts") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_posts_reposts_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_posts_reposts.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "get_posts_reposts") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_rules_cursor_creation(self): - """Test that get_rules can be used with Cursor.""" - method = getattr(self.tweets_client, "get_rules") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getRules should support pagination") - - - def test_get_rules_cursor_pages(self): - """Test pagination with pages() for get_rules.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.tweets_client, "get_rules") - test_cursor = cursor(method, max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_rules_cursor_items(self): - """Test pagination with items() for get_rules.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.tweets_client, "get_rules") - test_cursor = cursor(method, max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_rules_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_rules.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.tweets_client, "get_rules") - # Test with max_results parameter - test_cursor = cursor(method, max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_pagination_edge_cases(self): - """Test pagination edge cases.""" - with patch.object(self.client, "session") as mock_session: - # Test empty response - empty_response = Mock() - empty_response.status_code = 200 - # Use null/None for data to handle both list and object response types - empty_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - empty_response.raise_for_status.return_value = None - mock_session.get.return_value = empty_response - # Pick first paginatable method for testing - method = getattr(self.tweets_client, "get_lists_posts") - test_cursor = cursor(method, "test_id", max_results=10) - # Should handle empty responses gracefully - pages = list(test_cursor.pages(1)) - assert len(pages) == 1, "Should get one page even if empty" - items = list(test_cursor.items(10)) - assert len(items) == 0, "Should get no items from empty response" - - - def test_non_paginatable_method_raises_error(self): - """Test that non-paginatable methods raise PaginationError.""" - # Create a mock method that doesn't support pagination - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def test_cursor_class_functionality(self): - """Test basic Cursor class functionality.""" - # Test that Cursor can be imported and instantiated - from xdk.paginator import Cursor - assert Cursor is not None - # Test cursor factory function - from xdk.paginator import cursor as cursor_factory - assert cursor_factory is not None diff --git a/xdk/python/xdk/python/tests/tweets/test_structure.py b/xdk/python/xdk/python/tests/tweets/test_structure.py deleted file mode 100644 index d305c9c3..00000000 --- a/xdk/python/xdk/python/tests/tweets/test_structure.py +++ /dev/null @@ -1,2052 +0,0 @@ -""" -Auto-generated structural tests for Tweets client. - -This module contains tests that validate the structure and API surface -of the Tweets client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.tweets.client import TweetsClient -from xdk import Client - - -class TestTweetsStructure: - """Test the structure of TweetsClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.tweets_client = getattr(self.client, "tweets") - - - def test_stream_posts_sample10_exists(self): - """Test that stream_posts_sample10 method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "stream_posts_sample10", None) - assert ( - method is not None - ), f"Method stream_posts_sample10 does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"stream_posts_sample10 is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_sample10 should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_sample10" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_sample10_return_annotation(self): - """Test that stream_posts_sample10 has proper return type annotation.""" - method = getattr(TweetsClient, "stream_posts_sample10") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_sample10 should have return type annotation" - - - def test_get_spaces_posts_exists(self): - """Test that get_spaces_posts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_spaces_posts", None) - assert ( - method is not None - ), f"Method get_spaces_posts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_spaces_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_spaces_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_spaces_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_spaces_posts_return_annotation(self): - """Test that get_spaces_posts has proper return type annotation.""" - method = getattr(TweetsClient, "get_spaces_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_spaces_posts should have return type annotation" - - - def test_get_lists_posts_exists(self): - """Test that get_lists_posts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_lists_posts", None) - assert ( - method is not None - ), f"Method get_lists_posts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_lists_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_lists_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_lists_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_lists_posts_return_annotation(self): - """Test that get_lists_posts has proper return type annotation.""" - method = getattr(TweetsClient, "get_lists_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_lists_posts should have return type annotation" - - - def test_get_lists_posts_pagination_params(self): - """Test that get_lists_posts has pagination parameters.""" - method = getattr(TweetsClient, "get_lists_posts") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_lists_posts should have pagination parameters" - - - def test_get_posts_counts_recent_exists(self): - """Test that get_posts_counts_recent method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_posts_counts_recent", None) - assert ( - method is not None - ), f"Method get_posts_counts_recent does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_posts_counts_recent is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_posts_counts_recent should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "query", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_posts_counts_recent" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "start_time", - "end_time", - "since_id", - "until_id", - "next_token", - "pagination_token", - "granularity", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_posts_counts_recent_return_annotation(self): - """Test that get_posts_counts_recent has proper return type annotation.""" - method = getattr(TweetsClient, "get_posts_counts_recent") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_posts_counts_recent should have return type annotation" - - - def test_search_posts_recent_exists(self): - """Test that search_posts_recent method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "search_posts_recent", None) - assert ( - method is not None - ), f"Method search_posts_recent does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"search_posts_recent is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"search_posts_recent should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "query", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from search_posts_recent" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "start_time", - "end_time", - "since_id", - "until_id", - "max_results", - "next_token", - "pagination_token", - "sort_order", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_search_posts_recent_return_annotation(self): - """Test that search_posts_recent has proper return type annotation.""" - method = getattr(TweetsClient, "search_posts_recent") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method search_posts_recent should have return type annotation" - - - def test_search_posts_recent_pagination_params(self): - """Test that search_posts_recent has pagination parameters.""" - method = getattr(TweetsClient, "search_posts_recent") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method search_posts_recent should have pagination parameters" - - - def test_get_posts_counts_all_exists(self): - """Test that get_posts_counts_all method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_posts_counts_all", None) - assert ( - method is not None - ), f"Method get_posts_counts_all does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_posts_counts_all is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_posts_counts_all should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "query", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_posts_counts_all" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "start_time", - "end_time", - "since_id", - "until_id", - "next_token", - "pagination_token", - "granularity", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_posts_counts_all_return_annotation(self): - """Test that get_posts_counts_all has proper return type annotation.""" - method = getattr(TweetsClient, "get_posts_counts_all") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_posts_counts_all should have return type annotation" - - - def test_stream_posts_firehose_exists(self): - """Test that stream_posts_firehose method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "stream_posts_firehose", None) - assert ( - method is not None - ), f"Method stream_posts_firehose does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"stream_posts_firehose is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_firehose should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_firehose_return_annotation(self): - """Test that stream_posts_firehose has proper return type annotation.""" - method = getattr(TweetsClient, "stream_posts_firehose") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose should have return type annotation" - - - def test_get_rule_counts_exists(self): - """Test that get_rule_counts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_rule_counts", None) - assert ( - method is not None - ), f"Method get_rule_counts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_rule_counts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_rule_counts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_rule_counts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_rule_counts_return_annotation(self): - """Test that get_rule_counts has proper return type annotation.""" - method = getattr(TweetsClient, "get_rule_counts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_rule_counts should have return type annotation" - - - def test_stream_posts_firehose_en_exists(self): - """Test that stream_posts_firehose_en method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "stream_posts_firehose_en", None) - assert ( - method is not None - ), f"Method stream_posts_firehose_en does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"stream_posts_firehose_en is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_firehose_en should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose_en" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_firehose_en_return_annotation(self): - """Test that stream_posts_firehose_en has proper return type annotation.""" - method = getattr(TweetsClient, "stream_posts_firehose_en") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose_en should have return type annotation" - - - def test_like_post_exists(self): - """Test that like_post method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "like_post", None) - assert method is not None, f"Method like_post does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"like_post is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"like_post should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from like_post" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_like_post_return_annotation(self): - """Test that like_post has proper return type annotation.""" - method = getattr(TweetsClient, "like_post") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method like_post should have return type annotation" - - - def test_get_posts_analytics_exists(self): - """Test that get_posts_analytics method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_posts_analytics", None) - assert ( - method is not None - ), f"Method get_posts_analytics does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_posts_analytics is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_posts_analytics should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "ids", - "end_time", - "start_time", - "granularity", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_posts_analytics" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_posts_analytics_return_annotation(self): - """Test that get_posts_analytics has proper return type annotation.""" - method = getattr(TweetsClient, "get_posts_analytics") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_posts_analytics should have return type annotation" - - - def test_stream_posts_firehose_ko_exists(self): - """Test that stream_posts_firehose_ko method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "stream_posts_firehose_ko", None) - assert ( - method is not None - ), f"Method stream_posts_firehose_ko does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"stream_posts_firehose_ko is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_firehose_ko should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose_ko" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_firehose_ko_return_annotation(self): - """Test that stream_posts_firehose_ko has proper return type annotation.""" - method = getattr(TweetsClient, "stream_posts_firehose_ko") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose_ko should have return type annotation" - - - def test_stream_posts_exists(self): - """Test that stream_posts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "stream_posts", None) - assert method is not None, f"Method stream_posts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"stream_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"stream_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_return_annotation(self): - """Test that stream_posts has proper return type annotation.""" - method = getattr(TweetsClient, "stream_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts should have return type annotation" - - - def test_get_posts_quoted_posts_exists(self): - """Test that get_posts_quoted_posts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_posts_quoted_posts", None) - assert ( - method is not None - ), f"Method get_posts_quoted_posts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_posts_quoted_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_posts_quoted_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_posts_quoted_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - "exclude", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_posts_quoted_posts_return_annotation(self): - """Test that get_posts_quoted_posts has proper return type annotation.""" - method = getattr(TweetsClient, "get_posts_quoted_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_posts_quoted_posts should have return type annotation" - - - def test_get_posts_quoted_posts_pagination_params(self): - """Test that get_posts_quoted_posts has pagination parameters.""" - method = getattr(TweetsClient, "get_posts_quoted_posts") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_posts_quoted_posts should have pagination parameters" - - - def test_get_users_mentions_exists(self): - """Test that get_users_mentions method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_users_mentions", None) - assert ( - method is not None - ), f"Method get_users_mentions does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_users_mentions is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_mentions should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_users_mentions" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "since_id", - "until_id", - "max_results", - "pagination_token", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_users_mentions_return_annotation(self): - """Test that get_users_mentions has proper return type annotation.""" - method = getattr(TweetsClient, "get_users_mentions") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_mentions should have return type annotation" - - - def test_get_users_mentions_pagination_params(self): - """Test that get_users_mentions has pagination parameters.""" - method = getattr(TweetsClient, "get_users_mentions") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_mentions should have pagination parameters" - - - def test_unlike_post_exists(self): - """Test that unlike_post method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "unlike_post", None) - assert method is not None, f"Method unlike_post does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"unlike_post is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"unlike_post should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - "tweet_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from unlike_post" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_unlike_post_return_annotation(self): - """Test that unlike_post has proper return type annotation.""" - method = getattr(TweetsClient, "unlike_post") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method unlike_post should have return type annotation" - - - def test_get_posts_by_id_exists(self): - """Test that get_posts_by_id method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_posts_by_id", None) - assert ( - method is not None - ), f"Method get_posts_by_id does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_posts_by_id is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_posts_by_id should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_posts_by_id" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_posts_by_id_return_annotation(self): - """Test that get_posts_by_id has proper return type annotation.""" - method = getattr(TweetsClient, "get_posts_by_id") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_posts_by_id should have return type annotation" - - - def test_delete_posts_exists(self): - """Test that delete_posts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "delete_posts", None) - assert method is not None, f"Method delete_posts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"delete_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"delete_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from delete_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_delete_posts_return_annotation(self): - """Test that delete_posts has proper return type annotation.""" - method = getattr(TweetsClient, "delete_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method delete_posts should have return type annotation" - - - def test_search_posts_all_exists(self): - """Test that search_posts_all method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "search_posts_all", None) - assert ( - method is not None - ), f"Method search_posts_all does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"search_posts_all is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"search_posts_all should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "query", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from search_posts_all" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "start_time", - "end_time", - "since_id", - "until_id", - "max_results", - "next_token", - "pagination_token", - "sort_order", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_search_posts_all_return_annotation(self): - """Test that search_posts_all has proper return type annotation.""" - method = getattr(TweetsClient, "search_posts_all") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method search_posts_all should have return type annotation" - - - def test_search_posts_all_pagination_params(self): - """Test that search_posts_all has pagination parameters.""" - method = getattr(TweetsClient, "search_posts_all") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method search_posts_all should have pagination parameters" - - - def test_hide_posts_reply_exists(self): - """Test that hide_posts_reply method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "hide_posts_reply", None) - assert ( - method is not None - ), f"Method hide_posts_reply does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"hide_posts_reply is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"hide_posts_reply should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "tweet_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from hide_posts_reply" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_hide_posts_reply_return_annotation(self): - """Test that hide_posts_reply has proper return type annotation.""" - method = getattr(TweetsClient, "hide_posts_reply") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method hide_posts_reply should have return type annotation" - - - def test_stream_posts_sample_exists(self): - """Test that stream_posts_sample method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "stream_posts_sample", None) - assert ( - method is not None - ), f"Method stream_posts_sample does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"stream_posts_sample is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_sample should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_sample" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_sample_return_annotation(self): - """Test that stream_posts_sample has proper return type annotation.""" - method = getattr(TweetsClient, "stream_posts_sample") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_sample should have return type annotation" - - - def test_get_users_timeline_exists(self): - """Test that get_users_timeline method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_users_timeline", None) - assert ( - method is not None - ), f"Method get_users_timeline does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_users_timeline is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_timeline should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_users_timeline" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "since_id", - "until_id", - "max_results", - "pagination_token", - "exclude", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_users_timeline_return_annotation(self): - """Test that get_users_timeline has proper return type annotation.""" - method = getattr(TweetsClient, "get_users_timeline") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_timeline should have return type annotation" - - - def test_get_users_timeline_pagination_params(self): - """Test that get_users_timeline has pagination parameters.""" - method = getattr(TweetsClient, "get_users_timeline") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_timeline should have pagination parameters" - - - def test_get_users_posts_exists(self): - """Test that get_users_posts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_users_posts", None) - assert ( - method is not None - ), f"Method get_users_posts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_users_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_users_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "since_id", - "until_id", - "max_results", - "pagination_token", - "exclude", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_users_posts_return_annotation(self): - """Test that get_users_posts has proper return type annotation.""" - method = getattr(TweetsClient, "get_users_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_posts should have return type annotation" - - - def test_get_users_posts_pagination_params(self): - """Test that get_users_posts has pagination parameters.""" - method = getattr(TweetsClient, "get_users_posts") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_posts should have pagination parameters" - - - def test_get_spaces_buyers_exists(self): - """Test that get_spaces_buyers method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_spaces_buyers", None) - assert ( - method is not None - ), f"Method get_spaces_buyers does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_spaces_buyers is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_spaces_buyers should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_spaces_buyers" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "pagination_token", - "max_results", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_spaces_buyers_return_annotation(self): - """Test that get_spaces_buyers has proper return type annotation.""" - method = getattr(TweetsClient, "get_spaces_buyers") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_spaces_buyers should have return type annotation" - - - def test_get_spaces_buyers_pagination_params(self): - """Test that get_spaces_buyers has pagination parameters.""" - method = getattr(TweetsClient, "get_spaces_buyers") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_spaces_buyers should have pagination parameters" - - - def test_repost_post_exists(self): - """Test that repost_post method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "repost_post", None) - assert method is not None, f"Method repost_post does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"repost_post is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"repost_post should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from repost_post" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_repost_post_return_annotation(self): - """Test that repost_post has proper return type annotation.""" - method = getattr(TweetsClient, "repost_post") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method repost_post should have return type annotation" - - - def test_get_insights28_hr_exists(self): - """Test that get_insights28_hr method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_insights28_hr", None) - assert ( - method is not None - ), f"Method get_insights28_hr does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_insights28_hr is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_insights28_hr should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "tweet_ids", - "granularity", - "requested_metrics", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_insights28_hr" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_insights28_hr_return_annotation(self): - """Test that get_insights28_hr has proper return type annotation.""" - method = getattr(TweetsClient, "get_insights28_hr") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_insights28_hr should have return type annotation" - - - def test_get_posts_by_ids_exists(self): - """Test that get_posts_by_ids method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_posts_by_ids", None) - assert ( - method is not None - ), f"Method get_posts_by_ids does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_posts_by_ids is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_posts_by_ids should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "ids", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_posts_by_ids" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_posts_by_ids_return_annotation(self): - """Test that get_posts_by_ids has proper return type annotation.""" - method = getattr(TweetsClient, "get_posts_by_ids") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_posts_by_ids should have return type annotation" - - - def test_create_posts_exists(self): - """Test that create_posts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "create_posts", None) - assert method is not None, f"Method create_posts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"create_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"create_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from create_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_create_posts_return_annotation(self): - """Test that create_posts has proper return type annotation.""" - method = getattr(TweetsClient, "create_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method create_posts should have return type annotation" - - - def test_get_users_liked_posts_exists(self): - """Test that get_users_liked_posts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_users_liked_posts", None) - assert ( - method is not None - ), f"Method get_users_liked_posts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_users_liked_posts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_users_liked_posts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_users_liked_posts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_users_liked_posts_return_annotation(self): - """Test that get_users_liked_posts has proper return type annotation.""" - method = getattr(TweetsClient, "get_users_liked_posts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_users_liked_posts should have return type annotation" - - - def test_get_users_liked_posts_pagination_params(self): - """Test that get_users_liked_posts has pagination parameters.""" - method = getattr(TweetsClient, "get_users_liked_posts") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_users_liked_posts should have pagination parameters" - - - def test_get_insights_historical_exists(self): - """Test that get_insights_historical method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_insights_historical", None) - assert ( - method is not None - ), f"Method get_insights_historical does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_insights_historical is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_insights_historical should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "tweet_ids", - "end_time", - "start_time", - "granularity", - "requested_metrics", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_insights_historical" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_insights_historical_return_annotation(self): - """Test that get_insights_historical has proper return type annotation.""" - method = getattr(TweetsClient, "get_insights_historical") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_insights_historical should have return type annotation" - - - def test_stream_posts_firehose_ja_exists(self): - """Test that stream_posts_firehose_ja method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "stream_posts_firehose_ja", None) - assert ( - method is not None - ), f"Method stream_posts_firehose_ja does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"stream_posts_firehose_ja is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_firehose_ja should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose_ja" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_firehose_ja_return_annotation(self): - """Test that stream_posts_firehose_ja has proper return type annotation.""" - method = getattr(TweetsClient, "stream_posts_firehose_ja") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose_ja should have return type annotation" - - - def test_stream_posts_firehose_pt_exists(self): - """Test that stream_posts_firehose_pt method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "stream_posts_firehose_pt", None) - assert ( - method is not None - ), f"Method stream_posts_firehose_pt does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"stream_posts_firehose_pt is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"stream_posts_firehose_pt should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "partition", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from stream_posts_firehose_pt" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "backfill_minutes", - "start_time", - "end_time", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_stream_posts_firehose_pt_return_annotation(self): - """Test that stream_posts_firehose_pt has proper return type annotation.""" - method = getattr(TweetsClient, "stream_posts_firehose_pt") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method stream_posts_firehose_pt should have return type annotation" - - - def test_unrepost_post_exists(self): - """Test that unrepost_post method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "unrepost_post", None) - assert ( - method is not None - ), f"Method unrepost_post does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"unrepost_post is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"unrepost_post should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - "source_tweet_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from unrepost_post" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_unrepost_post_return_annotation(self): - """Test that unrepost_post has proper return type annotation.""" - method = getattr(TweetsClient, "unrepost_post") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method unrepost_post should have return type annotation" - - - def test_get_posts_reposts_exists(self): - """Test that get_posts_reposts method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_posts_reposts", None) - assert ( - method is not None - ), f"Method get_posts_reposts does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_posts_reposts is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"get_posts_reposts should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_posts_reposts" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "max_results", - "pagination_token", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_posts_reposts_return_annotation(self): - """Test that get_posts_reposts has proper return type annotation.""" - method = getattr(TweetsClient, "get_posts_reposts") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_posts_reposts should have return type annotation" - - - def test_get_posts_reposts_pagination_params(self): - """Test that get_posts_reposts has pagination parameters.""" - method = getattr(TweetsClient, "get_posts_reposts") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_posts_reposts should have pagination parameters" - - - def test_get_rules_exists(self): - """Test that get_rules method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "get_rules", None) - assert method is not None, f"Method get_rules does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"get_rules is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"get_rules should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_rules" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "ids", - "max_results", - "pagination_token", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_rules_return_annotation(self): - """Test that get_rules has proper return type annotation.""" - method = getattr(TweetsClient, "get_rules") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_rules should have return type annotation" - - - def test_get_rules_pagination_params(self): - """Test that get_rules has pagination parameters.""" - method = getattr(TweetsClient, "get_rules") - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have pagination-related parameters - pagination_params = [ - "pagination_token", - "max_results", - "next_token", - "cursor", - "limit", - ] - has_pagination_param = any(param in params for param in pagination_params) - assert ( - has_pagination_param - ), f"Paginated method get_rules should have pagination parameters" - - - def test_update_rules_exists(self): - """Test that update_rules method exists with correct signature.""" - # Check method exists - method = getattr(TweetsClient, "update_rules", None) - assert method is not None, f"Method update_rules does not exist on TweetsClient" - # Check method is callable - assert callable(method), f"update_rules is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"update_rules should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from update_rules" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "dry_run", - "delete_all", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_update_rules_return_annotation(self): - """Test that update_rules has proper return type annotation.""" - method = getattr(TweetsClient, "update_rules") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method update_rules should have return type annotation" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "stream_posts_sample10", - "get_spaces_posts", - "get_lists_posts", - "get_posts_counts_recent", - "search_posts_recent", - "get_posts_counts_all", - "stream_posts_firehose", - "get_rule_counts", - "stream_posts_firehose_en", - "like_post", - "get_posts_analytics", - "stream_posts_firehose_ko", - "stream_posts", - "get_posts_quoted_posts", - "get_users_mentions", - "unlike_post", - "get_posts_by_id", - "delete_posts", - "search_posts_all", - "hide_posts_reply", - "stream_posts_sample", - "get_users_timeline", - "get_users_posts", - "get_spaces_buyers", - "repost_post", - "get_insights28_hr", - "get_posts_by_ids", - "create_posts", - "get_users_liked_posts", - "get_insights_historical", - "stream_posts_firehose_ja", - "stream_posts_firehose_pt", - "unrepost_post", - "get_posts_reposts", - "get_rules", - "update_rules", - ] - for expected_method in expected_methods: - assert hasattr( - TweetsClient, expected_method - ), f"Expected method '{expected_method}' not found on TweetsClient" - assert callable( - getattr(TweetsClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/xdk/python/tests/usage/__init__.py b/xdk/python/xdk/python/tests/usage/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/usage/test_contracts.py b/xdk/python/xdk/python/tests/usage/test_contracts.py deleted file mode 100644 index 981c1657..00000000 --- a/xdk/python/xdk/python/tests/usage/test_contracts.py +++ /dev/null @@ -1,107 +0,0 @@ -""" -Auto-generated contract tests for Usage client. - -This module contains tests that validate the request/response contracts -of the Usage client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.usage.client import UsageClient -from xdk import Client - - -class TestUsageContracts: - """Test the API contracts of UsageClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.usage_client = getattr(self.client, "usage") - - - def test_get_usage_request_structure(self): - """Test get_usage request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.usage_client, "get_usage") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/usage/tweets" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_usage: {e}") - - - def test_get_usage_required_parameters(self): - """Test that get_usage handles parameters correctly.""" - method = getattr(self.usage_client, "get_usage") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_get_usage_response_structure(self): - """Test get_usage response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.usage_client, "get_usage") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/xdk/python/tests/usage/test_generic.py b/xdk/python/xdk/python/tests/usage/test_generic.py deleted file mode 100644 index b49fe951..00000000 --- a/xdk/python/xdk/python/tests/usage/test_generic.py +++ /dev/null @@ -1,122 +0,0 @@ -""" -Auto-generated generic tests for Usage client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.usage.client import UsageClient -from xdk import Client - - -class TestUsageGeneric: - """Generic tests for UsageClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.usage_client = getattr(self.client, "usage") - - - def test_client_exists(self): - """Test that UsageClient class exists and is importable.""" - assert UsageClient is not None - assert hasattr(UsageClient, "__name__") - assert UsageClient.__name__ == "UsageClient" - - - def test_client_initialization(self): - """Test that UsageClient can be initialized properly.""" - assert self.usage_client is not None - assert isinstance(self.usage_client, UsageClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(UsageClient) - if not name.startswith("_") and callable(getattr(UsageClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.usage_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "usage") - # Client should have standard Python object features - assert hasattr(self.usage_client, "__class__") - assert hasattr(self.usage_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.usage_client) - if not name.startswith("_") and callable(getattr(self.usage_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"UsageClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(UsageClient) - if not name.startswith("_") and callable(getattr(UsageClient, name)) - ] - for method_name in public_methods: - method = getattr(UsageClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/xdk/python/tests/usage/test_structure.py b/xdk/python/xdk/python/tests/usage/test_structure.py deleted file mode 100644 index 6f99fdf7..00000000 --- a/xdk/python/xdk/python/tests/usage/test_structure.py +++ /dev/null @@ -1,82 +0,0 @@ -""" -Auto-generated structural tests for Usage client. - -This module contains tests that validate the structure and API surface -of the Usage client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.usage.client import UsageClient -from xdk import Client - - -class TestUsageStructure: - """Test the structure of UsageClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.usage_client = getattr(self.client, "usage") - - - def test_get_usage_exists(self): - """Test that get_usage method exists with correct signature.""" - # Check method exists - method = getattr(UsageClient, "get_usage", None) - assert method is not None, f"Method get_usage does not exist on UsageClient" - # Check method is callable - assert callable(method), f"get_usage is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"get_usage should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_usage" - # Check optional parameters have defaults (excluding 'self') - optional_params = [ - "days", - ] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_usage_return_annotation(self): - """Test that get_usage has proper return type annotation.""" - method = getattr(UsageClient, "get_usage") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_usage should have return type annotation" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "get_usage", - ] - for expected_method in expected_methods: - assert hasattr( - UsageClient, expected_method - ), f"Expected method '{expected_method}' not found on UsageClient" - assert callable( - getattr(UsageClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/xdk/python/tests/users/__init__.py b/xdk/python/xdk/python/tests/users/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/users/test_generic.py b/xdk/python/xdk/python/tests/users/test_generic.py deleted file mode 100644 index b3154535..00000000 --- a/xdk/python/xdk/python/tests/users/test_generic.py +++ /dev/null @@ -1,122 +0,0 @@ -""" -Auto-generated generic tests for Users client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.users.client import UsersClient -from xdk import Client - - -class TestUsersGeneric: - """Generic tests for UsersClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.users_client = getattr(self.client, "users") - - - def test_client_exists(self): - """Test that UsersClient class exists and is importable.""" - assert UsersClient is not None - assert hasattr(UsersClient, "__name__") - assert UsersClient.__name__ == "UsersClient" - - - def test_client_initialization(self): - """Test that UsersClient can be initialized properly.""" - assert self.users_client is not None - assert isinstance(self.users_client, UsersClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(UsersClient) - if not name.startswith("_") and callable(getattr(UsersClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.users_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "users") - # Client should have standard Python object features - assert hasattr(self.users_client, "__class__") - assert hasattr(self.users_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.users_client) - if not name.startswith("_") and callable(getattr(self.users_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"UsersClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(UsersClient) - if not name.startswith("_") and callable(getattr(UsersClient, name)) - ] - for method_name in public_methods: - method = getattr(UsersClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/xdk/python/tests/users/test_pagination.py b/xdk/python/xdk/python/tests/users/test_pagination.py deleted file mode 100644 index 486bc327..00000000 --- a/xdk/python/xdk/python/tests/users/test_pagination.py +++ /dev/null @@ -1,1687 +0,0 @@ -""" -Auto-generated pagination tests for Users client. - -This module contains tests that validate pagination functionality -using the Cursor class for methods that support pagination. - -Generated automatically - do not edit manually. -""" - -import pytest -from unittest.mock import Mock, patch -from xdk.users.client import UsersClient -from xdk import Client, Cursor, cursor, PaginationError - - -class TestUsersPagination: - """Test pagination functionality for UsersClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.users_client = getattr(self.client, "users") - - - def test_get_users_blocking_cursor_creation(self): - """Test that get_users_blocking can be used with Cursor.""" - method = getattr(self.users_client, "get_users_blocking") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersBlocking should support pagination") - - - def test_get_users_blocking_cursor_pages(self): - """Test pagination with pages() for get_users_blocking.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.users_client, "get_users_blocking") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_blocking_cursor_items(self): - """Test pagination with items() for get_users_blocking.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.users_client, "get_users_blocking") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_blocking_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_blocking.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.users_client, "get_users_blocking") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_lists_members_cursor_creation(self): - """Test that get_lists_members can be used with Cursor.""" - method = getattr(self.users_client, "get_lists_members") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getListsMembers should support pagination") - - - def test_get_lists_members_cursor_pages(self): - """Test pagination with pages() for get_lists_members.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.users_client, "get_lists_members") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_lists_members_cursor_items(self): - """Test pagination with items() for get_lists_members.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.users_client, "get_lists_members") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_lists_members_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_lists_members.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.users_client, "get_lists_members") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_users_reposts_of_me_cursor_creation(self): - """Test that get_users_reposts_of_me can be used with Cursor.""" - method = getattr(self.users_client, "get_users_reposts_of_me") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersRepostsOfMe should support pagination") - - - def test_get_users_reposts_of_me_cursor_pages(self): - """Test pagination with pages() for get_users_reposts_of_me.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.users_client, "get_users_reposts_of_me") - test_cursor = cursor(method, max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_reposts_of_me_cursor_items(self): - """Test pagination with items() for get_users_reposts_of_me.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.users_client, "get_users_reposts_of_me") - test_cursor = cursor(method, max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_reposts_of_me_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_reposts_of_me.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.users_client, "get_users_reposts_of_me") - # Test with max_results parameter - test_cursor = cursor(method, max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_search_users_cursor_creation(self): - """Test that search_users can be used with Cursor.""" - method = getattr(self.users_client, "search_users") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_query", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method searchUsers should support pagination") - - - def test_search_users_cursor_pages(self): - """Test pagination with pages() for search_users.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.users_client, "search_users") - test_cursor = cursor(method, "test_query", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_search_users_cursor_items(self): - """Test pagination with items() for search_users.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.users_client, "search_users") - test_cursor = cursor(method, "test_query", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_search_users_pagination_parameters(self): - """Test that pagination parameters are handled correctly for search_users.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.users_client, "search_users") - # Test with max_results parameter - test_cursor = cursor(method, "test_query", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_query", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "next_token" in second_params - ), "Second request should include next_token" - assert ( - second_params["next_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_users_followers_cursor_creation(self): - """Test that get_users_followers can be used with Cursor.""" - method = getattr(self.users_client, "get_users_followers") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersFollowers should support pagination") - - - def test_get_users_followers_cursor_pages(self): - """Test pagination with pages() for get_users_followers.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.users_client, "get_users_followers") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_followers_cursor_items(self): - """Test pagination with items() for get_users_followers.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.users_client, "get_users_followers") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_followers_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_followers.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.users_client, "get_users_followers") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_users_following_cursor_creation(self): - """Test that get_users_following can be used with Cursor.""" - method = getattr(self.users_client, "get_users_following") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersFollowing should support pagination") - - - def test_get_users_following_cursor_pages(self): - """Test pagination with pages() for get_users_following.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.users_client, "get_users_following") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_following_cursor_items(self): - """Test pagination with items() for get_users_following.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.users_client, "get_users_following") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_following_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_following.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.users_client, "get_users_following") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_posts_liking_users_cursor_creation(self): - """Test that get_posts_liking_users can be used with Cursor.""" - method = getattr(self.users_client, "get_posts_liking_users") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getPostsLikingUsers should support pagination") - - - def test_get_posts_liking_users_cursor_pages(self): - """Test pagination with pages() for get_posts_liking_users.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.users_client, "get_posts_liking_users") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_posts_liking_users_cursor_items(self): - """Test pagination with items() for get_posts_liking_users.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.users_client, "get_posts_liking_users") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_posts_liking_users_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_posts_liking_users.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.users_client, "get_posts_liking_users") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_posts_reposted_by_cursor_creation(self): - """Test that get_posts_reposted_by can be used with Cursor.""" - method = getattr(self.users_client, "get_posts_reposted_by") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getPostsRepostedBy should support pagination") - - - def test_get_posts_reposted_by_cursor_pages(self): - """Test pagination with pages() for get_posts_reposted_by.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.users_client, "get_posts_reposted_by") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_posts_reposted_by_cursor_items(self): - """Test pagination with items() for get_posts_reposted_by.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.users_client, "get_posts_reposted_by") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_posts_reposted_by_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_posts_reposted_by.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.users_client, "get_posts_reposted_by") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_lists_followers_cursor_creation(self): - """Test that get_lists_followers can be used with Cursor.""" - method = getattr(self.users_client, "get_lists_followers") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getListsFollowers should support pagination") - - - def test_get_lists_followers_cursor_pages(self): - """Test pagination with pages() for get_lists_followers.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.users_client, "get_lists_followers") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_lists_followers_cursor_items(self): - """Test pagination with items() for get_lists_followers.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.users_client, "get_lists_followers") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_lists_followers_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_lists_followers.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.users_client, "get_lists_followers") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_get_users_muting_cursor_creation(self): - """Test that get_users_muting can be used with Cursor.""" - method = getattr(self.users_client, "get_users_muting") - # Should be able to create cursor without error - try: - test_cursor = cursor(method, "test_id", max_results=10) - assert test_cursor is not None - assert isinstance(test_cursor, Cursor) - except PaginationError: - pytest.fail(f"Method getUsersMuting should support pagination") - - - def test_get_users_muting_cursor_pages(self): - """Test pagination with pages() for get_users_muting.""" - with patch.object(self.client, "session") as mock_session: - # Mock first page response - first_page_response = Mock() - first_page_response.status_code = 200 - first_page_response.json.return_value = { - "data": [{"id": "1", "name": "Item 1"}, {"id": "2", "name": "Item 2"}], - "meta": {"next_token": "next_page_token", "result_count": 2}, - } - first_page_response.raise_for_status.return_value = None - # Mock second page response (no next token = end of pagination) - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": [{"id": "3", "name": "Item 3"}], - "meta": {"result_count": 1}, - } - second_page_response.raise_for_status.return_value = None - # Return different responses for consecutive calls - mock_session.get.side_effect = [first_page_response, second_page_response] - # Test pagination - method = getattr(self.users_client, "get_users_muting") - test_cursor = cursor(method, "test_id", max_results=2) - pages = list(test_cursor.pages(2)) # Limit to 2 pages - assert len(pages) == 2, f"Should get 2 pages, got {len(pages)}" - # Verify first page - first_page = pages[0] - assert hasattr(first_page, "data") - first_data = getattr(first_page, "data") - assert len(first_data) == 2, "First page should have 2 items" - # Verify second page - second_page = pages[1] - assert hasattr(second_page, "data") - second_data = getattr(second_page, "data") - assert len(second_data) == 1, "Second page should have 1 item" - - - def test_get_users_muting_cursor_items(self): - """Test pagination with items() for get_users_muting.""" - with patch.object(self.client, "session") as mock_session: - # Mock response with paginated data - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": [ - {"id": "1", "name": "Item 1"}, - {"id": "2", "name": "Item 2"}, - {"id": "3", "name": "Item 3"}, - ], - "meta": { - "result_count": 3 - # No next_token = single page - }, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Test item iteration - method = getattr(self.users_client, "get_users_muting") - test_cursor = cursor(method, "test_id", max_results=10) - items = list(test_cursor.items(5)) # Limit to 5 items - assert len(items) == 3, f"Should get 3 items, got {len(items)}" - # Verify items have expected structure - for item in items: - assert "id" in item or hasattr( - item, "id" - ), "Items should have 'id' field" - - - def test_get_users_muting_pagination_parameters(self): - """Test that pagination parameters are handled correctly for get_users_muting.""" - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - method = getattr(self.users_client, "get_users_muting") - # Test with max_results parameter - test_cursor = cursor(method, "test_id", max_results=5) - list(test_cursor.pages(1)) # Trigger one request - # Verify max_results was passed in request - call_args = mock_session.get.call_args - if call_args and "params" in call_args[1]: - params = call_args[1]["params"] - assert ( - "max_results" in params - ), "max_results should be in request parameters" - # Test with pagination token (simulate second page request) - mock_session.reset_mock() - mock_response_with_token = Mock() - mock_response_with_token.status_code = 200 - mock_response_with_token.json.return_value = { - "data": [{"id": "1"}], - "meta": {"next_token": "next_token_value", "result_count": 1}, - } - mock_response_with_token.raise_for_status.return_value = None - second_page_response = Mock() - second_page_response.status_code = 200 - second_page_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - second_page_response.raise_for_status.return_value = None - mock_session.get.side_effect = [ - mock_response_with_token, - second_page_response, - ] - test_cursor = cursor(method, "test_id", max_results=1) - pages = list(test_cursor.pages(2)) - # Should have made 2 requests - assert ( - mock_session.get.call_count == 2 - ), "Should make 2 requests for 2 pages" - # Second request should include pagination token - second_call_args = mock_session.get.call_args_list[1] - if ( - second_call_args - and len(second_call_args) > 1 - and "params" in second_call_args[1] - ): - second_params = second_call_args[1]["params"] - assert ( - "pagination_token" in second_params - ), "Second request should include pagination_token" - assert ( - second_params["pagination_token"] == "next_token_value" - ), "Pagination token should be passed correctly" - - - def test_pagination_edge_cases(self): - """Test pagination edge cases.""" - with patch.object(self.client, "session") as mock_session: - # Test empty response - empty_response = Mock() - empty_response.status_code = 200 - # Use null/None for data to handle both list and object response types - empty_response.json.return_value = { - "data": None, - "meta": {"result_count": 0}, - } - empty_response.raise_for_status.return_value = None - mock_session.get.return_value = empty_response - # Pick first paginatable method for testing - method = getattr(self.users_client, "get_users_blocking") - test_cursor = cursor(method, "test_id", max_results=10) - # Should handle empty responses gracefully - pages = list(test_cursor.pages(1)) - assert len(pages) == 1, "Should get one page even if empty" - items = list(test_cursor.items(10)) - assert len(items) == 0, "Should get no items from empty response" - - - def test_non_paginatable_method_raises_error(self): - """Test that non-paginatable methods raise PaginationError.""" - # Create a mock method that doesn't support pagination - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - def non_paginatable_method(id: str) -> dict: - return {"id": id} - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def non_paginatable_method(id: str) -> dict: - return {"id": id} - - with pytest.raises(PaginationError): - cursor(non_paginatable_method) - - - def test_cursor_class_functionality(self): - """Test basic Cursor class functionality.""" - # Test that Cursor can be imported and instantiated - from xdk.paginator import Cursor - assert Cursor is not None - # Test cursor factory function - from xdk.paginator import cursor as cursor_factory - assert cursor_factory is not None diff --git a/xdk/python/xdk/python/tests/webhooks/__init__.py b/xdk/python/xdk/python/tests/webhooks/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/xdk/python/xdk/python/tests/webhooks/test_contracts.py b/xdk/python/xdk/python/tests/webhooks/test_contracts.py deleted file mode 100644 index fe0c2e21..00000000 --- a/xdk/python/xdk/python/tests/webhooks/test_contracts.py +++ /dev/null @@ -1,368 +0,0 @@ -""" -Auto-generated contract tests for Webhooks client. - -This module contains tests that validate the request/response contracts -of the Webhooks client against the OpenAPI specification. - -Generated automatically - do not edit manually. -""" - -import pytest -import json -from unittest.mock import Mock, patch -from xdk.webhooks.client import WebhooksClient -from xdk import Client - - -class TestWebhooksContracts: - """Test the API contracts of WebhooksClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.webhooks_client = getattr(self.client, "webhooks") - - - def test_validate_webhooks_request_structure(self): - """Test validate_webhooks request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.put.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["webhook_id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.webhooks_client, "validate_webhooks") - result = method(**kwargs) - # Verify the request was made - mock_session.put.assert_called_once() - # Verify request structure - call_args = mock_session.put.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/webhooks/{webhook_id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for validate_webhooks: {e}") - - - def test_validate_webhooks_required_parameters(self): - """Test that validate_webhooks handles parameters correctly.""" - method = getattr(self.webhooks_client, "validate_webhooks") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.put.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_validate_webhooks_response_structure(self): - """Test validate_webhooks response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.put.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["webhook_id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.webhooks_client, "validate_webhooks") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_delete_webhooks_request_structure(self): - """Test delete_webhooks request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - kwargs["webhook_id"] = "test_value" - # Add request body if required - # Call the method - try: - method = getattr(self.webhooks_client, "delete_webhooks") - result = method(**kwargs) - # Verify the request was made - mock_session.delete.assert_called_once() - # Verify request structure - call_args = mock_session.delete.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/webhooks/{webhook_id}" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for delete_webhooks: {e}") - - - def test_delete_webhooks_required_parameters(self): - """Test that delete_webhooks handles parameters correctly.""" - method = getattr(self.webhooks_client, "delete_webhooks") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.delete.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_delete_webhooks_response_structure(self): - """Test delete_webhooks response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.delete.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - kwargs["webhook_id"] = "test" - # Add request body if required - # Call method and verify response structure - method = getattr(self.webhooks_client, "delete_webhooks") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_get_webhooks_request_structure(self): - """Test get_webhooks request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Call the method - try: - method = getattr(self.webhooks_client, "get_webhooks") - result = method(**kwargs) - # Verify the request was made - mock_session.get.assert_called_once() - # Verify request structure - call_args = mock_session.get.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/webhooks" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for get_webhooks: {e}") - - - def test_get_webhooks_required_parameters(self): - """Test that get_webhooks handles parameters correctly.""" - method = getattr(self.webhooks_client, "get_webhooks") - # No required parameters, method should be callable without args - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = {} - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - try: - method() - except Exception as e: - pytest.fail(f"Method with no required params should be callable: {e}") - - - def test_get_webhooks_response_structure(self): - """Test get_webhooks response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.get.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Call method and verify response structure - method = getattr(self.webhooks_client, "get_webhooks") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) - - - def test_create_webhooks_request_structure(self): - """Test create_webhooks request structure.""" - # Mock the session to capture request details - with patch.object(self.client, "session") as mock_session: - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "data": None, - } - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare test parameters - kwargs = {} - # Add required parameters - # Add request body if required - # Import and create proper request model instance - from xdk.webhooks.models import CreatewebhooksRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatewebhooksRequest() - # Call the method - try: - method = getattr(self.webhooks_client, "create_webhooks") - result = method(**kwargs) - # Verify the request was made - mock_session.post.assert_called_once() - # Verify request structure - call_args = mock_session.post.call_args - # Check URL structure - called_url = ( - call_args[0][0] if call_args[0] else call_args[1].get("url", "") - ) - expected_path = "/2/webhooks" - assert expected_path.replace("{", "").replace( - "}", "" - ) in called_url or any( - param in called_url for param in ["test_", "42"] - ), f"URL should contain path template elements: {called_url}" - # Verify response structure - assert result is not None, "Method should return a result" - except Exception as e: - pytest.fail(f"Contract test failed for create_webhooks: {e}") - - - def test_create_webhooks_required_parameters(self): - """Test that create_webhooks handles parameters correctly.""" - method = getattr(self.webhooks_client, "create_webhooks") - # Test with missing required parameters - mock the request to avoid network calls - with patch.object(self.client, "session") as mock_session: - # Mock a 400 response (typical for missing required parameters) - mock_response = Mock() - mock_response.status_code = 400 - mock_response.json.return_value = {"error": "Missing required parameters"} - mock_response.raise_for_status.side_effect = Exception("Bad Request") - mock_session.post.return_value = mock_response - # Call without required parameters should either raise locally or via server response - with pytest.raises((TypeError, ValueError, Exception)): - method() - - - def test_create_webhooks_response_structure(self): - """Test create_webhooks response structure validation.""" - with patch.object(self.client, "session") as mock_session: - # Create mock response with expected structure - mock_response_data = { - "data": None, - } - mock_response = Mock() - mock_response.status_code = 200 - mock_response.json.return_value = mock_response_data - mock_response.raise_for_status.return_value = None - mock_session.post.return_value = mock_response - # Prepare minimal valid parameters - kwargs = {} - # Add request body if required - # Import and create proper request model instance - from xdk.webhooks.models import CreatewebhooksRequest - # Create instance with minimal valid data (empty instance should work for most cases) - kwargs["body"] = CreatewebhooksRequest() - # Call method and verify response structure - method = getattr(self.webhooks_client, "create_webhooks") - result = method(**kwargs) - # Verify response object has expected attributes - # Optional field - just check it doesn't cause errors if accessed - try: - getattr(result, "data", None) - except Exception as e: - pytest.fail( - f"Accessing optional field 'data' should not cause errors: {e}" - ) diff --git a/xdk/python/xdk/python/tests/webhooks/test_generic.py b/xdk/python/xdk/python/tests/webhooks/test_generic.py deleted file mode 100644 index c5f539a1..00000000 --- a/xdk/python/xdk/python/tests/webhooks/test_generic.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -Auto-generated generic tests for Webhooks client. - -This module contains general tests that validate the overall client -functionality, imports, and error handling that don't need to be -repeated for each operation. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from unittest.mock import Mock, patch -from xdk.webhooks.client import WebhooksClient -from xdk import Client - - -class TestWebhooksGeneric: - """Generic tests for WebhooksClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.webhooks_client = getattr(self.client, "webhooks") - - - def test_client_exists(self): - """Test that WebhooksClient class exists and is importable.""" - assert WebhooksClient is not None - assert hasattr(WebhooksClient, "__name__") - assert WebhooksClient.__name__ == "WebhooksClient" - - - def test_client_initialization(self): - """Test that WebhooksClient can be initialized properly.""" - assert self.webhooks_client is not None - assert isinstance(self.webhooks_client, WebhooksClient) - - - def test_imports_work(self): - """Test that all expected imports work correctly.""" - expected_imports = ["typing", "requests", "pydantic"] - for import_name in expected_imports: - try: - __import__(import_name) - except ImportError as e: - pytest.fail(f"Expected import '{import_name}' failed: {e}") - - - def test_error_responses_handling(self): - """Test that error responses are handled correctly across all methods.""" - with patch.object(self.client, "session") as mock_session: - # Test 404 response - mock_response = Mock() - mock_response.status_code = 404 - mock_response.raise_for_status.side_effect = Exception("Not Found") - mock_session.get.return_value = mock_response - mock_session.post.return_value = mock_response - mock_session.put.return_value = mock_response - mock_session.delete.return_value = mock_response - # Get first available method for testing error handling - client_methods = [ - name - for name in dir(WebhooksClient) - if not name.startswith("_") and callable(getattr(WebhooksClient, name)) - ] - if client_methods: - method_name = client_methods[0] - method = getattr(self.webhooks_client, method_name) - # Try calling the method and expect an exception - with pytest.raises(Exception): - try: - # Try with no args first - method() - except TypeError: - # If it needs args, try with basic test args - try: - method("test_id") - except TypeError: - # If it needs more specific args, try with kwargs - method(id="test_id", query="test") - - - def test_client_has_expected_base_functionality(self): - """Test that the client has expected base functionality.""" - # Should be able to access the client through main Client - assert hasattr(self.client, "webhooks") - # Client should have standard Python object features - assert hasattr(self.webhooks_client, "__class__") - assert hasattr(self.webhooks_client, "__dict__") - # Should have at least one public method - public_methods = [ - name - for name in dir(self.webhooks_client) - if not name.startswith("_") - and callable(getattr(self.webhooks_client, name)) - ] - assert ( - len(public_methods) > 0 - ), f"WebhooksClient should have at least one public method" - - - def test_client_method_signatures_are_valid(self): - """Test that all client methods have valid Python signatures.""" - public_methods = [ - name - for name in dir(WebhooksClient) - if not name.startswith("_") and callable(getattr(WebhooksClient, name)) - ] - for method_name in public_methods: - method = getattr(WebhooksClient, method_name) - # Should be able to get signature without error - try: - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter (if it's an instance method) - if params: - assert ( - params[0] == "self" - ), f"Method {method_name} should have 'self' as first parameter" - except (ValueError, TypeError) as e: - pytest.fail(f"Method {method_name} has invalid signature: {e}") diff --git a/xdk/python/xdk/python/tests/webhooks/test_structure.py b/xdk/python/xdk/python/tests/webhooks/test_structure.py deleted file mode 100644 index b134323c..00000000 --- a/xdk/python/xdk/python/tests/webhooks/test_structure.py +++ /dev/null @@ -1,224 +0,0 @@ -""" -Auto-generated structural tests for Webhooks client. - -This module contains tests that validate the structure and API surface -of the Webhooks client. These tests ensure that all expected methods -exist and have the correct signatures. - -Generated automatically - do not edit manually. -""" - -import pytest -import inspect -from typing import get_type_hints -from xdk.webhooks.client import WebhooksClient -from xdk import Client - - -class TestWebhooksStructure: - """Test the structure of WebhooksClient.""" - - - def setup_class(self): - """Set up test fixtures.""" - self.client = Client(base_url="https://api.example.com") - self.webhooks_client = getattr(self.client, "webhooks") - - - def test_validate_webhooks_exists(self): - """Test that validate_webhooks method exists with correct signature.""" - # Check method exists - method = getattr(WebhooksClient, "validate_webhooks", None) - assert ( - method is not None - ), f"Method validate_webhooks does not exist on WebhooksClient" - # Check method is callable - assert callable(method), f"validate_webhooks is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"validate_webhooks should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "webhook_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from validate_webhooks" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_validate_webhooks_return_annotation(self): - """Test that validate_webhooks has proper return type annotation.""" - method = getattr(WebhooksClient, "validate_webhooks") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method validate_webhooks should have return type annotation" - - - def test_delete_webhooks_exists(self): - """Test that delete_webhooks method exists with correct signature.""" - # Check method exists - method = getattr(WebhooksClient, "delete_webhooks", None) - assert ( - method is not None - ), f"Method delete_webhooks does not exist on WebhooksClient" - # Check method is callable - assert callable(method), f"delete_webhooks is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"delete_webhooks should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [ - "webhook_id", - ] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from delete_webhooks" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_delete_webhooks_return_annotation(self): - """Test that delete_webhooks has proper return type annotation.""" - method = getattr(WebhooksClient, "delete_webhooks") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method delete_webhooks should have return type annotation" - - - def test_get_webhooks_exists(self): - """Test that get_webhooks method exists with correct signature.""" - # Check method exists - method = getattr(WebhooksClient, "get_webhooks", None) - assert ( - method is not None - ), f"Method get_webhooks does not exist on WebhooksClient" - # Check method is callable - assert callable(method), f"get_webhooks is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert len(params) >= 1, f"get_webhooks should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from get_webhooks" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_get_webhooks_return_annotation(self): - """Test that get_webhooks has proper return type annotation.""" - method = getattr(WebhooksClient, "get_webhooks") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method get_webhooks should have return type annotation" - - - def test_create_webhooks_exists(self): - """Test that create_webhooks method exists with correct signature.""" - # Check method exists - method = getattr(WebhooksClient, "create_webhooks", None) - assert ( - method is not None - ), f"Method create_webhooks does not exist on WebhooksClient" - # Check method is callable - assert callable(method), f"create_webhooks is not callable" - # Check method signature - sig = inspect.signature(method) - params = list(sig.parameters.keys()) - # Should have 'self' as first parameter - assert ( - len(params) >= 1 - ), f"create_webhooks should have at least 'self' parameter" - assert ( - params[0] == "self" - ), f"First parameter should be 'self', got '{params[0]}'" - # Check required parameters exist (excluding 'self') - required_params = [] - for required_param in required_params: - assert ( - required_param in params - ), f"Required parameter '{required_param}' missing from create_webhooks" - # Check optional parameters have defaults (excluding 'self') - optional_params = [] - for optional_param in optional_params: - if optional_param in params: - param_obj = sig.parameters[optional_param] - assert ( - param_obj.default is not inspect.Parameter.empty - ), f"Optional parameter '{optional_param}' should have a default value" - - - def test_create_webhooks_return_annotation(self): - """Test that create_webhooks has proper return type annotation.""" - method = getattr(WebhooksClient, "create_webhooks") - sig = inspect.signature(method) - # Check return annotation exists - assert ( - sig.return_annotation is not inspect.Signature.empty - ), f"Method create_webhooks should have return type annotation" - - - def test_all_expected_methods_exist(self): - """Test that all expected methods exist on the client.""" - expected_methods = [ - "validate_webhooks", - "delete_webhooks", - "get_webhooks", - "create_webhooks", - ] - for expected_method in expected_methods: - assert hasattr( - WebhooksClient, expected_method - ), f"Expected method '{expected_method}' not found on WebhooksClient" - assert callable( - getattr(WebhooksClient, expected_method) - ), f"'{expected_method}' exists but is not callable" diff --git a/xdk/python/xdk/python/xdk/__init__.py b/xdk/python/xdk/python/xdk/__init__.py deleted file mode 100644 index de02b42c..00000000 --- a/xdk/python/xdk/python/xdk/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -""" -XDK Python SDK. - -A Python SDK for the X API. -""" - -from .client import Client -from .paginator import Cursor, cursor, PaginationError - -__version__ = "0.1.0" -__all__ = ["Client", "Cursor", "cursor", "PaginationError"] diff --git a/xdk/python/xdk/python/xdk/aaasubscriptions/__init__.py b/xdk/python/xdk/python/xdk/aaasubscriptions/__init__.py deleted file mode 100644 index f9c93143..00000000 --- a/xdk/python/xdk/python/xdk/aaasubscriptions/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -AAASubscriptions module for the X API. - -This module provides access to the AAASubscriptions endpoints of the X API. -""" - -from .client import AaasubscriptionsClient - -__all__ = ["AaasubscriptionsClient"] diff --git a/xdk/python/xdk/python/xdk/aaasubscriptions/client.py b/xdk/python/xdk/python/xdk/aaasubscriptions/client.py deleted file mode 100644 index a0965998..00000000 --- a/xdk/python/xdk/python/xdk/aaasubscriptions/client.py +++ /dev/null @@ -1,75 +0,0 @@ -""" -AAASubscriptions client for the X API. - -This module provides a client for interacting with the AAASubscriptions endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - CreateaccountactivitysubscriptionRequest, - CreateaccountactivitysubscriptionResponse, -) - - -class AaasubscriptionsClient: - """Client for AAASubscriptions operations""" - - - def __init__(self, client: Client): - self.client = client - - - def create_account_activity_subscription( - self, - webhook_id: str, - body: Optional[CreateaccountactivitysubscriptionRequest] = None, - ) -> CreateaccountactivitysubscriptionResponse: - """ - Create subscription - Creates an Account Activity subscription for the user and the given webhook. - Args: - webhook_id: The webhook ID to check subscription against. - body: Request body - Returns: - CreateaccountactivitysubscriptionResponse: Response data - """ - url = ( - self.client.base_url - + "/2/account_activity/webhooks/{webhook_id}/subscriptions/all" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{webhook_id}", str(webhook_id)) - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return CreateaccountactivitysubscriptionResponse.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/aaasubscriptions/models.py b/xdk/python/xdk/python/xdk/aaasubscriptions/models.py deleted file mode 100644 index 6f5925c0..00000000 --- a/xdk/python/xdk/python/xdk/aaasubscriptions/models.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -AAASubscriptions models for the X API. - -This module provides models for the AAASubscriptions endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for createAccountActivitySubscription - - -class CreateaccountactivitysubscriptionRequest(BaseModel): - """Request model for createAccountActivitySubscription""" - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreateaccountactivitysubscriptionResponse(BaseModel): - """Response model for createAccountActivitySubscription""" - - data: Optional["CreateaccountactivitysubscriptionResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreateaccountactivitysubscriptionResponseData(BaseModel): - """Nested model for CreateaccountactivitysubscriptionResponseData""" - - subscribed: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/python/xdk/account_activity/__init__.py b/xdk/python/xdk/python/xdk/account_activity/__init__.py deleted file mode 100644 index 799b0a4d..00000000 --- a/xdk/python/xdk/python/xdk/account_activity/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Account_Activity module for the X API. - -This module provides access to the Account_Activity endpoints of the X API. -""" - -from .client import AccountActivityClient - -__all__ = ["AccountActivityClient"] diff --git a/xdk/python/xdk/python/xdk/account_activity/client.py b/xdk/python/xdk/python/xdk/account_activity/client.py deleted file mode 100644 index 5878c319..00000000 --- a/xdk/python/xdk/python/xdk/account_activity/client.py +++ /dev/null @@ -1,244 +0,0 @@ -""" -Account_Activity client for the X API. - -This module provides a client for interacting with the Account_Activity endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - GetaccountactivitysubscriptioncountResponse, - ValidateaccountactivitysubscriptionResponse, - GetaccountactivitysubscriptionsResponse, - DeleteaccountactivitysubscriptionResponse, - CreateaccountactivityreplayjobResponse, -) - - -class AccountActivityClient: - """Client for Account_Activity operations""" - - - def __init__(self, client: Client): - self.client = client - - - def get_account_activity_subscription_count( - self, - ) -> GetaccountactivitysubscriptioncountResponse: - """ - Get subscription count - Retrieves a count of currently active Account Activity subscriptions. - Returns: - GetaccountactivitysubscriptioncountResponse: Response data - """ - url = self.client.base_url + "/2/account_activity/subscriptions/count" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetaccountactivitysubscriptioncountResponse.model_validate(response_data) - - - def validate_account_activity_subscription( - self, - webhook_id: str, - ) -> ValidateaccountactivitysubscriptionResponse: - """ - Validate subscription - Checks a user’s Account Activity subscription for a given webhook. - Args: - webhook_id: The webhook ID to check subscription against. - Returns: - ValidateaccountactivitysubscriptionResponse: Response data - """ - url = ( - self.client.base_url - + "/2/account_activity/webhooks/{webhook_id}/subscriptions/all" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{webhook_id}", str(webhook_id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return ValidateaccountactivitysubscriptionResponse.model_validate(response_data) - - - def get_account_activity_subscriptions( - self, - webhook_id: str, - ) -> GetaccountactivitysubscriptionsResponse: - """ - Get subscriptions - Retrieves a list of all active subscriptions for a given webhook. - Args: - webhook_id: The webhook ID to pull subscriptions for. - Returns: - GetaccountactivitysubscriptionsResponse: Response data - """ - url = ( - self.client.base_url - + "/2/account_activity/webhooks/{webhook_id}/subscriptions/all/list" - ) - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - url = url.replace("{webhook_id}", str(webhook_id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetaccountactivitysubscriptionsResponse.model_validate(response_data) - - - def delete_account_activity_subscription( - self, - webhook_id: str, - user_id: str, - ) -> DeleteaccountactivitysubscriptionResponse: - """ - Delete subscription - Deletes an Account Activity subscription for the given webhook and user ID. - Args: - webhook_id: The webhook ID to check subscription against. - Args: - user_id: User ID to unsubscribe from. - Returns: - DeleteaccountactivitysubscriptionResponse: Response data - """ - url = ( - self.client.base_url - + "/2/account_activity/webhooks/{webhook_id}/subscriptions/{user_id}/all" - ) - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - url = url.replace("{webhook_id}", str(webhook_id)) - url = url.replace("{user_id}", str(user_id)) - headers = {} - # Make the request - response = self.client.session.delete( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return DeleteaccountactivitysubscriptionResponse.model_validate(response_data) - - - def create_account_activity_replay_job( - self, - webhook_id: str, - from_date: str, - to_date: str, - ) -> CreateaccountactivityreplayjobResponse: - """ - Create replay job - Creates a replay job to retrieve activities from up to the past 5 days for all subscriptions associated with a given webhook. - Args: - webhook_id: The unique identifier for the webhook configuration. - Args: - from_date: The oldest (starting) UTC timestamp (inclusive) from which events will be provided, in `yyyymmddhhmm` format. - Args: - to_date: The latest (ending) UTC timestamp (exclusive) up to which events will be provided, in `yyyymmddhhmm` format. - Returns: - CreateaccountactivityreplayjobResponse: Response data - """ - url = ( - self.client.base_url - + "/2/account_activity/replay/webhooks/{webhook_id}/subscriptions/all" - ) - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if from_date is not None: - params["from_date"] = from_date - if to_date is not None: - params["to_date"] = to_date - url = url.replace("{webhook_id}", str(webhook_id)) - headers = {} - # Make the request - response = self.client.session.post( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return CreateaccountactivityreplayjobResponse.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/account_activity/models.py b/xdk/python/xdk/python/xdk/account_activity/models.py deleted file mode 100644 index dd478a50..00000000 --- a/xdk/python/xdk/python/xdk/account_activity/models.py +++ /dev/null @@ -1,140 +0,0 @@ -""" -Account_Activity models for the X API. - -This module provides models for the Account_Activity endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for getAccountActivitySubscriptionCount - - -class GetaccountactivitysubscriptioncountResponse(BaseModel): - """Response model for getAccountActivitySubscriptionCount""" - - data: Optional["GetaccountactivitysubscriptioncountResponseData"] = Field( - description="The count of active subscriptions across all webhooks", - default_factory=dict, - ) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetaccountactivitysubscriptioncountResponseData(BaseModel): - """Nested model for GetaccountactivitysubscriptioncountResponseData""" - - account_name: Optional[str] = None - provisioned_count: Optional[str] = None - subscriptions_count_all: Optional[str] = None - subscriptions_count_direct_messages: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for validateAccountActivitySubscription - - -class ValidateaccountactivitysubscriptionResponse(BaseModel): - """Response model for validateAccountActivitySubscription""" - - data: Optional["ValidateaccountactivitysubscriptionResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class ValidateaccountactivitysubscriptionResponseData(BaseModel): - """Nested model for ValidateaccountactivitysubscriptionResponseData""" - - subscribed: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getAccountActivitySubscriptions - - -class GetaccountactivitysubscriptionsResponse(BaseModel): - """Response model for getAccountActivitySubscriptions""" - - data: Optional["GetaccountactivitysubscriptionsResponseData"] = Field( - description="The list of active subscriptions for a specified webhook", - default_factory=dict, - ) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetaccountactivitysubscriptionsResponseData(BaseModel): - """Nested model for GetaccountactivitysubscriptionsResponseData""" - - application_id: Optional[str] = None - subscriptions: Optional[List] = None - webhook_id: Optional[str] = None - webhook_url: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for deleteAccountActivitySubscription - - -class DeleteaccountactivitysubscriptionResponse(BaseModel): - """Response model for deleteAccountActivitySubscription""" - - data: Optional["DeleteaccountactivitysubscriptionResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class DeleteaccountactivitysubscriptionResponseData(BaseModel): - """Nested model for DeleteaccountactivitysubscriptionResponseData""" - - subscribed: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for createAccountActivityReplayJob - - -class CreateaccountactivityreplayjobResponse(BaseModel): - """Response model for createAccountActivityReplayJob""" - - created_at: Optional[str] = None - job_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/python/xdk/bookmarks/__init__.py b/xdk/python/xdk/python/xdk/bookmarks/__init__.py deleted file mode 100644 index 17ca7bbc..00000000 --- a/xdk/python/xdk/python/xdk/bookmarks/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Bookmarks module for the X API. - -This module provides access to the Bookmarks endpoints of the X API. -""" - -from .client import BookmarksClient - -__all__ = ["BookmarksClient"] diff --git a/xdk/python/xdk/python/xdk/bookmarks/client.py b/xdk/python/xdk/python/xdk/bookmarks/client.py deleted file mode 100644 index 030b9ba8..00000000 --- a/xdk/python/xdk/python/xdk/bookmarks/client.py +++ /dev/null @@ -1,302 +0,0 @@ -""" -Bookmarks client for the X API. - -This module provides a client for interacting with the Bookmarks endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - DeleteusersbookmarkResponse, - GetusersbookmarksResponse, - CreateusersbookmarkRequest, - CreateusersbookmarkResponse, - GetusersbookmarkfoldersResponse, - GetusersbookmarksbyfolderidResponse, -) - - -class BookmarksClient: - """Client for Bookmarks operations""" - - - def __init__(self, client: Client): - self.client = client - - - def delete_users_bookmark( - self, - id: str, - tweet_id: str, - ) -> DeleteusersbookmarkResponse: - """ - Delete Bookmark - Removes a Post from the authenticated user’s Bookmarks by its ID. - Args: - id: The ID of the authenticated source User whose bookmark is to be removed. - Args: - tweet_id: The ID of the Post that the source User is removing from bookmarks. - Returns: - DeleteusersbookmarkResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/bookmarks/{tweet_id}" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - url = url.replace("{tweet_id}", str(tweet_id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.delete( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.delete( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return DeleteusersbookmarkResponse.model_validate(response_data) - - - def get_users_bookmarks( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetusersbookmarksResponse: - """ - Get Bookmarks - Retrieves a list of Posts bookmarked by the authenticated user. - Args: - id: The ID of the authenticated source User for whom to return results. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetusersbookmarksResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/bookmarks" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetusersbookmarksResponse.model_validate(response_data) - - - def create_users_bookmark( - self, - id: str, - body: CreateusersbookmarkRequest, - ) -> CreateusersbookmarkResponse: - """ - Create Bookmark - Adds a post to the authenticated user’s bookmarks. - Args: - id: The ID of the authenticated source User for whom to add bookmarks. - body: Request body - Returns: - CreateusersbookmarkResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/bookmarks" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return CreateusersbookmarkResponse.model_validate(response_data) - - - def get_users_bookmark_folders( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - ) -> GetusersbookmarkfoldersResponse: - """ - Get Bookmark folders - Retrieves a list of Bookmark folders created by the authenticated user. - Args: - id: The ID of the authenticated source User for whom to return results. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Returns: - GetusersbookmarkfoldersResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/bookmarks/folders" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetusersbookmarkfoldersResponse.model_validate(response_data) - - - def get_users_bookmarks_by_folder_id( - self, - id: str, - folder_id: str, - ) -> GetusersbookmarksbyfolderidResponse: - """ - Get Bookmarks by folder ID - Retrieves Posts in a specific Bookmark folder by its ID for the authenticated user. - Args: - id: The ID of the authenticated source User for whom to return results. - Args: - folder_id: The ID of the Bookmark Folder that the authenticated User is trying to fetch Posts for. - Returns: - GetusersbookmarksbyfolderidResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/bookmarks/folders/{folder_id}" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - url = url.replace("{folder_id}", str(folder_id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetusersbookmarksbyfolderidResponse.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/bookmarks/models.py b/xdk/python/xdk/python/xdk/bookmarks/models.py deleted file mode 100644 index 84c21209..00000000 --- a/xdk/python/xdk/python/xdk/bookmarks/models.py +++ /dev/null @@ -1,169 +0,0 @@ -""" -Bookmarks models for the X API. - -This module provides models for the Bookmarks endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for deleteUsersBookmark - - -class DeleteusersbookmarkResponse(BaseModel): - """Response model for deleteUsersBookmark""" - - data: Optional["DeleteusersbookmarkResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class DeleteusersbookmarkResponseData(BaseModel): - """Nested model for DeleteusersbookmarkResponseData""" - - bookmarked: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersBookmarks - - -class GetusersbookmarksResponse(BaseModel): - """Response model for getUsersBookmarks""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetusersbookmarksResponseIncludes"] = None - meta: Optional["GetusersbookmarksResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbookmarksResponseIncludes(BaseModel): - """Nested model for GetusersbookmarksResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbookmarksResponseMeta(BaseModel): - """Nested model for GetusersbookmarksResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for createUsersBookmark - - -class CreateusersbookmarkRequest(BaseModel): - """Request model for createUsersBookmark""" - - tweet_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreateusersbookmarkResponse(BaseModel): - """Response model for createUsersBookmark""" - - data: Optional["CreateusersbookmarkResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreateusersbookmarkResponseData(BaseModel): - """Nested model for CreateusersbookmarkResponseData""" - - bookmarked: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersBookmarkFolders - - -class GetusersbookmarkfoldersResponse(BaseModel): - """Response model for getUsersBookmarkFolders""" - - data: Optional["GetusersbookmarkfoldersResponseData"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbookmarkfoldersResponseData(BaseModel): - """Nested model for GetusersbookmarkfoldersResponseData""" - - id: Optional[str] = None - name: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersBookmarksByFolderId - - -class GetusersbookmarksbyfolderidResponse(BaseModel): - """Response model for getUsersBookmarksByFolderId""" - - data: Optional["GetusersbookmarksbyfolderidResponseData"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbookmarksbyfolderidResponseData(BaseModel): - """Nested model for GetusersbookmarksbyfolderidResponseData""" - - id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/python/xdk/client.py b/xdk/python/xdk/python/xdk/client.py deleted file mode 100644 index a9154648..00000000 --- a/xdk/python/xdk/python/xdk/client.py +++ /dev/null @@ -1,164 +0,0 @@ -""" -Main client for the X API. - -This module provides a client for interacting with the X API. -""" - -import requests -from typing import Dict, List, Optional, Union, Any, Callable - -from .oauth2_auth import OAuth2PKCEAuth -from .paginator import Cursor, cursor, PaginationError - -from .account_activity.client import AccountActivityClient - -from .aaasubscriptions.client import AaasubscriptionsClient - -from .trends.client import TrendsClient - -from .bookmarks.client import BookmarksClient - -from .lists.client import ListsClient - -from .webhooks.client import WebhooksClient - -from .tweets.client import TweetsClient - -from .communities.client import CommunitiesClient - -from .usage.client import UsageClient - -from .likes.client import LikesClient - -from .direct_messages.client import DirectMessagesClient - -from .media.client import MediaClient - -from .connection.client import ConnectionClient - -from .spaces.client import SpacesClient - -from .compliance.client import ComplianceClient - -from .users.client import UsersClient - -from .stream.client import StreamClient - -from .general.client import GeneralClient - -from .community_notes.client import CommunityNotesClient - - -class Client: - """Client for interacting with the X API.""" - - - def __init__( - self, - base_url: str = "https://api.twitter.com", - bearer_token: str = None, - client_id: str = None, - client_secret: str = None, - redirect_uri: str = None, - token: Dict[str, Any] = None, - scope: str = None, - ): - """Initialize the X API client. - Args: - base_url: The base URL for the X API. - bearer_token: The bearer token for the X API. - client_id: The client ID for the X API. - client_secret: The client secret for the X API. - redirect_uri: The redirect URI for OAuth2 authorization. - token: An existing OAuth2 token dictionary (if available). - scope: Space-separated list of scopes for OAuth2 authorization. - """ - self.session = requests.Session() - self.base_url = base_url - self.bearer_token = bearer_token - # Set up OAuth2 PKCE authentication if credentials are provided - self.oauth2_auth = None - if client_id or token: - self.oauth2_auth = OAuth2PKCEAuth( - base_url=base_url, - client_id=client_id, - client_secret=client_secret, - redirect_uri=redirect_uri, - token=token, - scope=scope, - ) - # Initialize clients for each tag - self.account_activity = AccountActivityClient(self) - self.aaasubscriptions = AaasubscriptionsClient(self) - self.trends = TrendsClient(self) - self.bookmarks = BookmarksClient(self) - self.lists = ListsClient(self) - self.webhooks = WebhooksClient(self) - self.tweets = TweetsClient(self) - self.communities = CommunitiesClient(self) - self.usage = UsageClient(self) - self.likes = LikesClient(self) - self.direct_messages = DirectMessagesClient(self) - self.media = MediaClient(self) - self.connection = ConnectionClient(self) - self.spaces = SpacesClient(self) - self.compliance = ComplianceClient(self) - self.users = UsersClient(self) - self.stream = StreamClient(self) - self.general = GeneralClient(self) - self.community_notes = CommunityNotesClient(self) - - @property - - - def oauth2_session(self): - """Get the OAuth2 session if available.""" - if self.oauth2_auth: - return self.oauth2_auth.oauth2_session - return None - - @property - - - def token(self): - """Get the current OAuth2 token if available.""" - if self.oauth2_auth: - return self.oauth2_auth.token - return None - - @property - - - def access_token(self): - """Get the current access token if available.""" - if self.oauth2_auth: - return self.oauth2_auth.access_token - return None - - - def get_authorization_url(self): - """Get the authorization URL for the OAuth2 PKCE flow.""" - if not self.oauth2_auth: - raise ValueError("OAuth2 credentials not configured") - return self.oauth2_auth.get_authorization_url() - - - def fetch_token(self, authorization_response): - """Fetch token using authorization response.""" - if not self.oauth2_auth: - raise ValueError("OAuth2 credentials not configured") - return self.oauth2_auth.fetch_token(authorization_response) - - - def refresh_token(self): - """Refresh the OAuth2 token.""" - if not self.oauth2_auth: - raise ValueError("OAuth2 credentials not configured") - return self.oauth2_auth.refresh_token() - - - def is_token_expired(self): - """Check if the OAuth2 token is expired.""" - if not self.oauth2_auth: - return True - return self.oauth2_auth.is_token_expired() diff --git a/xdk/python/xdk/python/xdk/communities/__init__.py b/xdk/python/xdk/python/xdk/communities/__init__.py deleted file mode 100644 index be73767a..00000000 --- a/xdk/python/xdk/python/xdk/communities/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Communities module for the X API. - -This module provides access to the Communities endpoints of the X API. -""" - -from .client import CommunitiesClient - -__all__ = ["CommunitiesClient"] diff --git a/xdk/python/xdk/python/xdk/communities/client.py b/xdk/python/xdk/python/xdk/communities/client.py deleted file mode 100644 index 1b37a0a0..00000000 --- a/xdk/python/xdk/python/xdk/communities/client.py +++ /dev/null @@ -1,140 +0,0 @@ -""" -Communities client for the X API. - -This module provides a client for interacting with the Communities endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - GetcommunitiesbyidResponse, - SearchcommunitiesResponse, -) - - -class CommunitiesClient: - """Client for Communities operations""" - - - def __init__(self, client: Client): - self.client = client - - - def get_communities_by_id( - self, - id: str, - community_fields: List = None, - ) -> GetcommunitiesbyidResponse: - """ - Get Community by ID - Retrieves details of a specific Community by its ID. - Args: - id: The ID of the Community. - Args: - community_fields: A comma separated list of Community fields to display. - Returns: - GetcommunitiesbyidResponse: Response data - """ - url = self.client.base_url + "/2/communities/{id}" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if community_fields is not None: - params["community.fields"] = ",".join( - str(item) for item in community_fields - ) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetcommunitiesbyidResponse.model_validate(response_data) - - - def search_communities( - self, - query: str, - max_results: int = None, - next_token: str = None, - pagination_token: str = None, - community_fields: List = None, - ) -> SearchcommunitiesResponse: - """ - Search Communities - Retrieves a list of Communities matching the specified search query. - Args: - query: Query to search communities. - Args: - max_results: The maximum number of search results to be returned by a request. - Args: - next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - pagination_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - community_fields: A comma separated list of Community fields to display. - Returns: - SearchcommunitiesResponse: Response data - """ - url = self.client.base_url + "/2/communities/search" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if query is not None: - params["query"] = query - if max_results is not None: - params["max_results"] = max_results - if next_token is not None: - params["next_token"] = next_token - if pagination_token is not None: - params["pagination_token"] = pagination_token - if community_fields is not None: - params["community.fields"] = ",".join( - str(item) for item in community_fields - ) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return SearchcommunitiesResponse.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/communities/models.py b/xdk/python/xdk/python/xdk/communities/models.py deleted file mode 100644 index 1928a63c..00000000 --- a/xdk/python/xdk/python/xdk/communities/models.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -Communities models for the X API. - -This module provides models for the Communities endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for getCommunitiesById - - -class GetcommunitiesbyidResponse(BaseModel): - """Response model for getCommunitiesById""" - - data: Optional["GetcommunitiesbyidResponseData"] = Field( - description="A X Community is a curated group of Posts.", default_factory=dict - ) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetcommunitiesbyidResponseData(BaseModel): - """Nested model for GetcommunitiesbyidResponseData""" - - created_at: Optional[str] = None - id: Optional[str] = None - name: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for searchCommunities - - -class SearchcommunitiesResponse(BaseModel): - """Response model for searchCommunities""" - - data: Optional[List] = None - errors: Optional[List] = None - meta: Optional["SearchcommunitiesResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class SearchcommunitiesResponseMeta(BaseModel): - """Nested model for SearchcommunitiesResponseMeta""" - - next_token: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/python/xdk/community_notes/__init__.py b/xdk/python/xdk/python/xdk/community_notes/__init__.py deleted file mode 100644 index 12ffe09f..00000000 --- a/xdk/python/xdk/python/xdk/community_notes/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Community_Notes module for the X API. - -This module provides access to the Community_Notes endpoints of the X API. -""" - -from .client import CommunityNotesClient - -__all__ = ["CommunityNotesClient"] diff --git a/xdk/python/xdk/python/xdk/community_notes/client.py b/xdk/python/xdk/python/xdk/community_notes/client.py deleted file mode 100644 index a39a5b0a..00000000 --- a/xdk/python/xdk/python/xdk/community_notes/client.py +++ /dev/null @@ -1,254 +0,0 @@ -""" -Community_Notes client for the X API. - -This module provides a client for interacting with the Community_Notes endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - CreatenotesRequest, - CreatenotesResponse, - SearchnoteswrittenResponse, - SearchforeligiblepostsResponse, - DeletenotesResponse, -) - - -class CommunityNotesClient: - """Client for Community_Notes operations""" - - - def __init__(self, client: Client): - self.client = client - - - def create_notes( - self, - body: Optional[CreatenotesRequest] = None, - ) -> CreatenotesResponse: - """ - Create a Community Note - Creates a community note endpoint for LLM use case. - body: Request body - Returns: - CreatenotesResponse: Response data - """ - url = self.client.base_url + "/2/notes" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return CreatenotesResponse.model_validate(response_data) - - - def search_notes_written( - self, - test_mode: bool, - pagination_token: str = None, - max_results: int = None, - note_fields: List = None, - ) -> SearchnoteswrittenResponse: - """ - Search for Community Notes Written - Returns all the community notes written by the user. - Args: - test_mode: If true, return the notes the caller wrote for the test. If false, return the notes the caller wrote on the product. - Args: - pagination_token: Pagination token to get next set of posts eligible for notes. - Args: - max_results: Max results to return. - Args: - note_fields: A comma separated list of Note fields to display. - Returns: - SearchnoteswrittenResponse: Response data - """ - url = self.client.base_url + "/2/notes/search/notes_written" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if test_mode is not None: - params["test_mode"] = test_mode - if pagination_token is not None: - params["pagination_token"] = pagination_token - if max_results is not None: - params["max_results"] = max_results - if note_fields is not None: - params["note.fields"] = ",".join(str(item) for item in note_fields) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return SearchnoteswrittenResponse.model_validate(response_data) - - - def search_for_eligible_posts( - self, - test_mode: bool, - pagination_token: str = None, - max_results: int = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> SearchforeligiblepostsResponse: - """ - Search for Posts Eligible for Community Notes - Returns all the posts that are eligible for community notes. - Args: - test_mode: If true, return a list of posts that are for the test. If false, return a list of posts that the bots can write proposed notes on the product. - Args: - pagination_token: Pagination token to get next set of posts eligible for notes. - Args: - max_results: Max results to return. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - SearchforeligiblepostsResponse: Response data - """ - url = self.client.base_url + "/2/notes/search/posts_eligible_for_notes" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if test_mode is not None: - params["test_mode"] = test_mode - if pagination_token is not None: - params["pagination_token"] = pagination_token - if max_results is not None: - params["max_results"] = max_results - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return SearchforeligiblepostsResponse.model_validate(response_data) - - - def delete_notes( - self, - id: str, - ) -> DeletenotesResponse: - """ - Delete a Community Note - Deletes a community note. - Args: - id: The community note id to delete. - Returns: - DeletenotesResponse: Response data - """ - url = self.client.base_url + "/2/notes/{id}" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.delete( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.delete( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return DeletenotesResponse.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/community_notes/models.py b/xdk/python/xdk/python/xdk/community_notes/models.py deleted file mode 100644 index ab3fd386..00000000 --- a/xdk/python/xdk/python/xdk/community_notes/models.py +++ /dev/null @@ -1,163 +0,0 @@ -""" -Community_Notes models for the X API. - -This module provides models for the Community_Notes endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for createNotes - - -class CreatenotesRequest(BaseModel): - """Request model for createNotes""" - - info: Optional["CreatenotesRequestInfo"] = Field( - description="A X Community Note is a note on a Post.", default_factory=dict - ) - post_id: Optional[str] = None - test_mode: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatenotesResponse(BaseModel): - """Response model for createNotes""" - - data: Optional["CreatenotesResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatenotesRequestInfo(BaseModel): - """Nested model for CreatenotesRequestInfo""" - - classification: Optional[str] = None - misleading_tags: Optional[List] = None - text: Optional[str] = None - trustworthy_sources: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatenotesResponseData(BaseModel): - """Nested model for CreatenotesResponseData""" - - deleted: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for searchNotesWritten - - -class SearchnoteswrittenResponse(BaseModel): - """Response model for searchNotesWritten""" - - data: Optional[List] = None - errors: Optional[List] = None - meta: Optional["SearchnoteswrittenResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class SearchnoteswrittenResponseMeta(BaseModel): - """Nested model for SearchnoteswrittenResponseMeta""" - - next_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for searchForEligiblePosts - - -class SearchforeligiblepostsResponse(BaseModel): - """Response model for searchForEligiblePosts""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["SearchforeligiblepostsResponseIncludes"] = None - meta: Optional["SearchforeligiblepostsResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class SearchforeligiblepostsResponseIncludes(BaseModel): - """Nested model for SearchforeligiblepostsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class SearchforeligiblepostsResponseMeta(BaseModel): - """Nested model for SearchforeligiblepostsResponseMeta""" - - next_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for deleteNotes - - -class DeletenotesResponse(BaseModel): - """Response model for deleteNotes""" - - data: Optional["DeletenotesResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class DeletenotesResponseData(BaseModel): - """Nested model for DeletenotesResponseData""" - - id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/python/xdk/compliance/__init__.py b/xdk/python/xdk/python/xdk/compliance/__init__.py deleted file mode 100644 index afc20103..00000000 --- a/xdk/python/xdk/python/xdk/compliance/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Compliance module for the X API. - -This module provides access to the Compliance endpoints of the X API. -""" - -from .client import ComplianceClient - -__all__ = ["ComplianceClient"] diff --git a/xdk/python/xdk/python/xdk/compliance/client.py b/xdk/python/xdk/python/xdk/compliance/client.py deleted file mode 100644 index 4770dbd0..00000000 --- a/xdk/python/xdk/python/xdk/compliance/client.py +++ /dev/null @@ -1,371 +0,0 @@ -""" -Compliance client for the X API. - -This module provides a client for interacting with the Compliance endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - GetcompliancejobsResponse, - CreatecompliancejobsRequest, - CreatecompliancejobsResponse, - GetcompliancejobsbyidResponse, - StreamlikescomplianceResponse, - StreamuserscomplianceResponse, - StreamlabelscomplianceResponse, - StreampostscomplianceResponse, -) - - -class ComplianceClient: - """Client for Compliance operations""" - - - def __init__(self, client: Client): - self.client = client - - - def get_compliance_jobs( - self, - type: str, - status: str = None, - compliance_job_fields: List = None, - ) -> GetcompliancejobsResponse: - """ - Get Compliance Jobs - Retrieves a list of Compliance Jobs filtered by job type and optional status. - Args: - type: Type of Compliance Job to list. - Args: - status: Status of Compliance Job to list. - Args: - compliance_job_fields: A comma separated list of ComplianceJob fields to display. - Returns: - GetcompliancejobsResponse: Response data - """ - url = self.client.base_url + "/2/compliance/jobs" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if type is not None: - params["type"] = type - if status is not None: - params["status"] = status - if compliance_job_fields is not None: - params["compliance_job.fields"] = ",".join( - str(item) for item in compliance_job_fields - ) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetcompliancejobsResponse.model_validate(response_data) - - - def create_compliance_jobs( - self, - body: CreatecompliancejobsRequest, - ) -> CreatecompliancejobsResponse: - """ - Create Compliance Job - Creates a new Compliance Job for the specified job type. - body: A request to create a new batch compliance job. - Returns: - CreatecompliancejobsResponse: Response data - """ - url = self.client.base_url + "/2/compliance/jobs" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return CreatecompliancejobsResponse.model_validate(response_data) - - - def get_compliance_jobs_by_id( - self, - id: str, - compliance_job_fields: List = None, - ) -> GetcompliancejobsbyidResponse: - """ - Get Compliance Job by ID - Retrieves details of a specific Compliance Job by its ID. - Args: - id: The ID of the Compliance Job to retrieve. - Args: - compliance_job_fields: A comma separated list of ComplianceJob fields to display. - Returns: - GetcompliancejobsbyidResponse: Response data - """ - url = self.client.base_url + "/2/compliance/jobs/{id}" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if compliance_job_fields is not None: - params["compliance_job.fields"] = ",".join( - str(item) for item in compliance_job_fields - ) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetcompliancejobsbyidResponse.model_validate(response_data) - - - def stream_likes_compliance( - self, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - ) -> StreamlikescomplianceResponse: - """ - Stream Likes compliance data - Streams all compliance data related to Likes for Users. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Likes Compliance events will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp from which the Likes Compliance events will be provided. - Returns: - StreamlikescomplianceResponse: Response data - """ - url = self.client.base_url + "/2/likes/compliance/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamlikescomplianceResponse.model_validate(response_data) - - - def stream_users_compliance( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - ) -> StreamuserscomplianceResponse: - """ - Stream Users compliance data - Streams all compliance data related to Users. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the User Compliance events will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp from which the User Compliance events will be provided. - Returns: - StreamuserscomplianceResponse: Response data - """ - url = self.client.base_url + "/2/users/compliance/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamuserscomplianceResponse.model_validate(response_data) - - - def stream_labels_compliance( - self, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - ) -> StreamlabelscomplianceResponse: - """ - Stream Post labels - Streams all labeling events applied to Posts. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Post labels will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp from which the Post labels will be provided. - Returns: - StreamlabelscomplianceResponse: Response data - """ - url = self.client.base_url + "/2/tweets/label/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamlabelscomplianceResponse.model_validate(response_data) - - - def stream_posts_compliance( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - ) -> StreampostscomplianceResponse: - """ - Stream Posts compliance data - Streams all compliance data related to Posts. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Post Compliance events will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Post Compliance events will be provided. - Returns: - StreampostscomplianceResponse: Response data - """ - url = self.client.base_url + "/2/tweets/compliance/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreampostscomplianceResponse.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/compliance/models.py b/xdk/python/xdk/python/xdk/compliance/models.py deleted file mode 100644 index 5cdb03bb..00000000 --- a/xdk/python/xdk/python/xdk/compliance/models.py +++ /dev/null @@ -1,177 +0,0 @@ -""" -Compliance models for the X API. - -This module provides models for the Compliance endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for getComplianceJobs - - -class GetcompliancejobsResponse(BaseModel): - """Response model for getComplianceJobs""" - - data: Optional[List] = None - errors: Optional[List] = None - meta: Optional["GetcompliancejobsResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetcompliancejobsResponseMeta(BaseModel): - """Nested model for GetcompliancejobsResponseMeta""" - - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for createComplianceJobs - - -class CreatecompliancejobsRequest(BaseModel): - """Request model for createComplianceJobs""" - - name: Optional[str] = None - resumable: Optional[bool] = None - type: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatecompliancejobsResponse(BaseModel): - """Response model for createComplianceJobs""" - - data: Optional["CreatecompliancejobsResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatecompliancejobsResponseData(BaseModel): - """Nested model for CreatecompliancejobsResponseData""" - - created_at: Optional[str] = None - download_expires_at: Optional[str] = None - download_url: Optional[str] = None - id: Optional[str] = None - name: Optional[str] = None - status: Optional[str] = None - type: Optional[str] = None - upload_expires_at: Optional[str] = None - upload_url: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getComplianceJobsById - - -class GetcompliancejobsbyidResponse(BaseModel): - """Response model for getComplianceJobsById""" - - data: Optional["GetcompliancejobsbyidResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetcompliancejobsbyidResponseData(BaseModel): - """Nested model for GetcompliancejobsbyidResponseData""" - - created_at: Optional[str] = None - download_expires_at: Optional[str] = None - download_url: Optional[str] = None - id: Optional[str] = None - name: Optional[str] = None - status: Optional[str] = None - type: Optional[str] = None - upload_expires_at: Optional[str] = None - upload_url: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamLikesCompliance - - -class StreamlikescomplianceResponse(BaseModel): - """Response model for streamLikesCompliance""" - - data: Optional[Dict[str, Any]] = Field(default=None) - errors: Optional[List] = Field(default=None) - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamUsersCompliance - - -class StreamuserscomplianceResponse(BaseModel): - """Response model for streamUsersCompliance""" - - data: Optional[Any] = Field(default=None, description="User compliance data.") - errors: Optional[List] = Field(default=None) - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamLabelsCompliance - - -class StreamlabelscomplianceResponse(BaseModel): - """Response model for streamLabelsCompliance""" - - data: Optional[Any] = Field(default=None, description="Tweet label data.") - errors: Optional[List] = Field(default=None) - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamPostsCompliance - - -class StreampostscomplianceResponse(BaseModel): - """Response model for streamPostsCompliance""" - - data: Optional[Any] = Field(default=None, description="Tweet compliance data.") - errors: Optional[List] = Field(default=None) - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/python/xdk/connection/__init__.py b/xdk/python/xdk/python/xdk/connection/__init__.py deleted file mode 100644 index 02192af8..00000000 --- a/xdk/python/xdk/python/xdk/connection/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Connection module for the X API. - -This module provides access to the Connection endpoints of the X API. -""" - -from .client import ConnectionClient - -__all__ = ["ConnectionClient"] diff --git a/xdk/python/xdk/python/xdk/connection/client.py b/xdk/python/xdk/python/xdk/connection/client.py deleted file mode 100644 index 381eb0d8..00000000 --- a/xdk/python/xdk/python/xdk/connection/client.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -Connection client for the X API. - -This module provides a client for interacting with the Connection endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - DeleteallconnectionsResponse, -) - - -class ConnectionClient: - """Client for Connection operations""" - - - def __init__(self, client: Client): - self.client = client - - - def delete_all_connections( - self, - ) -> DeleteallconnectionsResponse: - """ - Terminate all connections - Terminates all active streaming connections for the authenticated application. - Returns: - DeleteallconnectionsResponse: Response data - """ - url = self.client.base_url + "/2/connections/all" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - headers = {} - # Make the request - response = self.client.session.delete( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return DeleteallconnectionsResponse.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/connection/models.py b/xdk/python/xdk/python/xdk/connection/models.py deleted file mode 100644 index 3ed1be7f..00000000 --- a/xdk/python/xdk/python/xdk/connection/models.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Connection models for the X API. - -This module provides models for the Connection endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for deleteAllConnections - - -class DeleteallconnectionsResponse(BaseModel): - """Response model for deleteAllConnections""" - - data: Optional["DeleteallconnectionsResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class DeleteallconnectionsResponseData(BaseModel): - """Nested model for DeleteallconnectionsResponseData""" - - killed_connections: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/python/xdk/direct_messages/__init__.py b/xdk/python/xdk/python/xdk/direct_messages/__init__.py deleted file mode 100644 index 11c905df..00000000 --- a/xdk/python/xdk/python/xdk/direct_messages/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Direct_Messages module for the X API. - -This module provides access to the Direct_Messages endpoints of the X API. -""" - -from .client import DirectMessagesClient - -__all__ = ["DirectMessagesClient"] diff --git a/xdk/python/xdk/python/xdk/direct_messages/client.py b/xdk/python/xdk/python/xdk/direct_messages/client.py deleted file mode 100644 index 50245c9d..00000000 --- a/xdk/python/xdk/python/xdk/direct_messages/client.py +++ /dev/null @@ -1,526 +0,0 @@ -""" -Direct_Messages client for the X API. - -This module provides a client for interacting with the Direct_Messages endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - CreatedmbyconversationidRequest, - CreatedmbyconversationidResponse, - CreatedmconversationsRequest, - CreatedmconversationsResponse, - GetdmeventsbyparticipantidResponse, - GetdmconversationsiddmeventsResponse, - GetdmeventsResponse, - CreatedmbyparticipantidRequest, - CreatedmbyparticipantidResponse, - GetdmeventsbyidResponse, - DeletedmeventsResponse, -) - - -class DirectMessagesClient: - """Client for Direct_Messages operations""" - - - def __init__(self, client: Client): - self.client = client - - - def create_dm_by_conversation_id( - self, - dm_conversation_id: str, - body: Optional[CreatedmbyconversationidRequest] = None, - ) -> Dict[str, Any]: - """ - Create DM message by conversation ID - Sends a new direct message to a specific conversation by its ID. - Args: - dm_conversation_id: The DM Conversation ID. - body: Request body - Returns: - CreatedmbyconversationidResponse: Response data - """ - url = self.client.base_url + "/2/dm_conversations/{dm_conversation_id}/messages" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{dm_conversation_id}", str(dm_conversation_id)) - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return CreatedmbyconversationidResponse.model_validate(response_data) - - - def create_dm_conversations( - self, - body: Optional[CreatedmconversationsRequest] = None, - ) -> Dict[str, Any]: - """ - Create DM conversation - Initiates a new direct message conversation with specified participants. - body: Request body - Returns: - CreatedmconversationsResponse: Response data - """ - url = self.client.base_url + "/2/dm_conversations" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return CreatedmconversationsResponse.model_validate(response_data) - - - def get_dm_events_by_participant_id( - self, - participant_id: str, - max_results: int = None, - pagination_token: str = None, - event_types: List = None, - dm_event_fields: List = None, - expansions: List = None, - media_fields: List = None, - user_fields: List = None, - tweet_fields: List = None, - ) -> GetdmeventsbyparticipantidResponse: - """ - Get DM events for a DM conversation - Retrieves direct message events for a specific conversation. - Args: - participant_id: The ID of the participant user for the One to One DM conversation. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - event_types: The set of event_types to include in the results. - Args: - dm_event_fields: A comma separated list of DmEvent fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetdmeventsbyparticipantidResponse: Response data - """ - url = ( - self.client.base_url + "/2/dm_conversations/with/{participant_id}/dm_events" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if event_types is not None: - params["event_types"] = ",".join(str(item) for item in event_types) - if dm_event_fields is not None: - params["dm_event.fields"] = ",".join(str(item) for item in dm_event_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{participant_id}", str(participant_id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetdmeventsbyparticipantidResponse.model_validate(response_data) - - - def get_dm_conversations_id_dm_events( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - event_types: List = None, - dm_event_fields: List = None, - expansions: List = None, - media_fields: List = None, - user_fields: List = None, - tweet_fields: List = None, - ) -> GetdmconversationsiddmeventsResponse: - """ - Get DM events for a DM conversation - Retrieves direct message events for a specific conversation. - Args: - id: The DM conversation ID. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - event_types: The set of event_types to include in the results. - Args: - dm_event_fields: A comma separated list of DmEvent fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetdmconversationsiddmeventsResponse: Response data - """ - url = self.client.base_url + "/2/dm_conversations/{id}/dm_events" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if event_types is not None: - params["event_types"] = ",".join(str(item) for item in event_types) - if dm_event_fields is not None: - params["dm_event.fields"] = ",".join(str(item) for item in dm_event_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetdmconversationsiddmeventsResponse.model_validate(response_data) - - - def get_dm_events( - self, - max_results: int = None, - pagination_token: str = None, - event_types: List = None, - dm_event_fields: List = None, - expansions: List = None, - media_fields: List = None, - user_fields: List = None, - tweet_fields: List = None, - ) -> GetdmeventsResponse: - """ - Get DM events - Retrieves a list of recent direct message events across all conversations. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - event_types: The set of event_types to include in the results. - Args: - dm_event_fields: A comma separated list of DmEvent fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetdmeventsResponse: Response data - """ - url = self.client.base_url + "/2/dm_events" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if event_types is not None: - params["event_types"] = ",".join(str(item) for item in event_types) - if dm_event_fields is not None: - params["dm_event.fields"] = ",".join(str(item) for item in dm_event_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetdmeventsResponse.model_validate(response_data) - - - def create_dm_by_participant_id( - self, - participant_id: str, - body: Optional[CreatedmbyparticipantidRequest] = None, - ) -> Dict[str, Any]: - """ - Create DM message by participant ID - Sends a new direct message to a specific participant by their ID. - Args: - participant_id: The ID of the recipient user that will receive the DM. - body: Request body - Returns: - CreatedmbyparticipantidResponse: Response data - """ - url = ( - self.client.base_url + "/2/dm_conversations/with/{participant_id}/messages" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{participant_id}", str(participant_id)) - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return CreatedmbyparticipantidResponse.model_validate(response_data) - - - def get_dm_events_by_id( - self, - event_id: str, - dm_event_fields: List = None, - expansions: List = None, - media_fields: List = None, - user_fields: List = None, - tweet_fields: List = None, - ) -> GetdmeventsbyidResponse: - """ - Get DM event by ID - Retrieves details of a specific direct message event by its ID. - Args: - event_id: dm event id. - Args: - dm_event_fields: A comma separated list of DmEvent fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetdmeventsbyidResponse: Response data - """ - url = self.client.base_url + "/2/dm_events/{event_id}" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if dm_event_fields is not None: - params["dm_event.fields"] = ",".join(str(item) for item in dm_event_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{event_id}", str(event_id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetdmeventsbyidResponse.model_validate(response_data) - - - def delete_dm_events( - self, - event_id: str, - ) -> DeletedmeventsResponse: - """ - Delete DM event - Deletes a specific direct message event by its ID, if owned by the authenticated user. - Args: - event_id: The ID of the direct-message event to delete. - Returns: - DeletedmeventsResponse: Response data - """ - url = self.client.base_url + "/2/dm_events/{event_id}" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{event_id}", str(event_id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.delete( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.delete( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return DeletedmeventsResponse.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/direct_messages/models.py b/xdk/python/xdk/python/xdk/direct_messages/models.py deleted file mode 100644 index bc393a21..00000000 --- a/xdk/python/xdk/python/xdk/direct_messages/models.py +++ /dev/null @@ -1,370 +0,0 @@ -""" -Direct_Messages models for the X API. - -This module provides models for the Direct_Messages endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for createDmByConversationId - - -class CreatedmbyconversationidRequest(BaseModel): - """Request model for createDmByConversationId""" - - attachments: Optional[List] = Field( - default=None, description="Attachments to a DM Event." - ) - text: Optional[str] = Field(default=None, description="Text of the message.") - attachments: Optional[List] = Field( - default=None, description="Attachments to a DM Event." - ) - text: Optional[str] = Field(default=None, description="Text of the message.") - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatedmbyconversationidResponse(BaseModel): - """Response model for createDmByConversationId""" - - data: Optional["CreatedmbyconversationidResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatedmbyconversationidResponseData(BaseModel): - """Nested model for CreatedmbyconversationidResponseData""" - - dm_conversation_id: Optional[str] = None - dm_event_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for createDmConversations - - -class CreatedmconversationsRequest(BaseModel): - """Request model for createDmConversations""" - - conversation_type: Optional[str] = None - message: Any = None - participant_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatedmconversationsResponse(BaseModel): - """Response model for createDmConversations""" - - data: Optional["CreatedmconversationsResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatedmconversationsResponseData(BaseModel): - """Nested model for CreatedmconversationsResponseData""" - - dm_conversation_id: Optional[str] = None - dm_event_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getDmEventsByParticipantId - - -class GetdmeventsbyparticipantidResponse(BaseModel): - """Response model for getDmEventsByParticipantId""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetdmeventsbyparticipantidResponseIncludes"] = None - meta: Optional["GetdmeventsbyparticipantidResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetdmeventsbyparticipantidResponseIncludes(BaseModel): - """Nested model for GetdmeventsbyparticipantidResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetdmeventsbyparticipantidResponseMeta(BaseModel): - """Nested model for GetdmeventsbyparticipantidResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getDmConversationsIdDmEvents - - -class GetdmconversationsiddmeventsResponse(BaseModel): - """Response model for getDmConversationsIdDmEvents""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetdmconversationsiddmeventsResponseIncludes"] = None - meta: Optional["GetdmconversationsiddmeventsResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetdmconversationsiddmeventsResponseIncludes(BaseModel): - """Nested model for GetdmconversationsiddmeventsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetdmconversationsiddmeventsResponseMeta(BaseModel): - """Nested model for GetdmconversationsiddmeventsResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getDmEvents - - -class GetdmeventsResponse(BaseModel): - """Response model for getDmEvents""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetdmeventsResponseIncludes"] = None - meta: Optional["GetdmeventsResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetdmeventsResponseIncludes(BaseModel): - """Nested model for GetdmeventsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetdmeventsResponseMeta(BaseModel): - """Nested model for GetdmeventsResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for createDmByParticipantId - - -class CreatedmbyparticipantidRequest(BaseModel): - """Request model for createDmByParticipantId""" - - attachments: Optional[List] = Field( - default=None, description="Attachments to a DM Event." - ) - text: Optional[str] = Field(default=None, description="Text of the message.") - attachments: Optional[List] = Field( - default=None, description="Attachments to a DM Event." - ) - text: Optional[str] = Field(default=None, description="Text of the message.") - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatedmbyparticipantidResponse(BaseModel): - """Response model for createDmByParticipantId""" - - data: Optional["CreatedmbyparticipantidResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatedmbyparticipantidResponseData(BaseModel): - """Nested model for CreatedmbyparticipantidResponseData""" - - dm_conversation_id: Optional[str] = None - dm_event_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getDmEventsById - - -class GetdmeventsbyidResponse(BaseModel): - """Response model for getDmEventsById""" - - data: Optional["GetdmeventsbyidResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - includes: Optional["GetdmeventsbyidResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetdmeventsbyidResponseData(BaseModel): - """Nested model for GetdmeventsbyidResponseData""" - - attachments: Optional["GetdmeventsbyidResponseDataAttachments"] = None - cashtags: Optional[List] = None - created_at: Optional[str] = None - dm_conversation_id: Optional[str] = None - event_type: Optional[str] = None - hashtags: Optional[List] = None - id: Optional[str] = None - mentions: Optional[List] = None - participant_ids: Optional[List] = None - referenced_tweets: Optional[List] = None - sender_id: Optional[str] = None - text: Optional[str] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetdmeventsbyidResponseDataAttachments(BaseModel): - """Nested model for GetdmeventsbyidResponseDataAttachments""" - - card_ids: Optional[List] = None - media_keys: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetdmeventsbyidResponseIncludes(BaseModel): - """Nested model for GetdmeventsbyidResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for deleteDmEvents - - -class DeletedmeventsResponse(BaseModel): - """Response model for deleteDmEvents""" - - data: Optional["DeletedmeventsResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class DeletedmeventsResponseData(BaseModel): - """Nested model for DeletedmeventsResponseData""" - - deleted: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/python/xdk/general/__init__.py b/xdk/python/xdk/python/xdk/general/__init__.py deleted file mode 100644 index 5de7148e..00000000 --- a/xdk/python/xdk/python/xdk/general/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -General module for the X API. - -This module provides access to the General endpoints of the X API. -""" - -from .client import GeneralClient - -__all__ = ["GeneralClient"] diff --git a/xdk/python/xdk/python/xdk/general/client.py b/xdk/python/xdk/python/xdk/general/client.py deleted file mode 100644 index 96739a35..00000000 --- a/xdk/python/xdk/python/xdk/general/client.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -General client for the X API. - -This module provides a client for interacting with the General endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - GetopenapispecResponse, -) - - -class GeneralClient: - """Client for General operations""" - - - def __init__(self, client: Client): - self.client = client - - - def get_open_api_spec( - self, - ) -> GetopenapispecResponse: - """ - Get OpenAPI Spec. - Retrieves the full OpenAPI Specification in JSON format. (See https://github.com/OAI/OpenAPI-Specification/blob/master/README.md) - Returns: - GetopenapispecResponse: Response data - """ - url = self.client.base_url + "/2/openapi.json" - params = {} - headers = {} - # Make the request - # This should only happend for the /2/openapi.json route - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetopenapispecResponse.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/general/models.py b/xdk/python/xdk/python/xdk/general/models.py deleted file mode 100644 index 1a4ecd07..00000000 --- a/xdk/python/xdk/python/xdk/general/models.py +++ /dev/null @@ -1,21 +0,0 @@ -""" -General models for the X API. - -This module provides models for the General endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for getOpenApiSpec - - -class GetopenapispecResponse(BaseModel): - """Response model for getOpenApiSpec""" - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/python/xdk/likes/__init__.py b/xdk/python/xdk/python/xdk/likes/__init__.py deleted file mode 100644 index 1a9af0b7..00000000 --- a/xdk/python/xdk/python/xdk/likes/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Likes module for the X API. - -This module provides access to the Likes endpoints of the X API. -""" - -from .client import LikesClient - -__all__ = ["LikesClient"] diff --git a/xdk/python/xdk/python/xdk/likes/client.py b/xdk/python/xdk/python/xdk/likes/client.py deleted file mode 100644 index c4e92069..00000000 --- a/xdk/python/xdk/python/xdk/likes/client.py +++ /dev/null @@ -1,177 +0,0 @@ -""" -Likes client for the X API. - -This module provides a client for interacting with the Likes endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - StreamlikesfirehoseResponse, - Streamlikessample10Response, -) - - -class LikesClient: - """Client for Likes operations""" - - - def __init__(self, client: Client): - self.client = client - - - def stream_likes_firehose( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - like_with_tweet_author_fields: List = None, - expansions: List = None, - user_fields: List = None, - tweet_fields: List = None, - ) -> StreamlikesfirehoseResponse: - """ - Stream all Likes - Streams all public Likes in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Likes will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - like_with_tweet_author_fields: A comma separated list of LikeWithTweetAuthor fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - StreamlikesfirehoseResponse: Response data - """ - url = self.client.base_url + "/2/likes/firehose/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if like_with_tweet_author_fields is not None: - params["like_with_tweet_author.fields"] = ",".join( - str(item) for item in like_with_tweet_author_fields - ) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamlikesfirehoseResponse.model_validate(response_data) - - - def stream_likes_sample10( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - like_with_tweet_author_fields: List = None, - expansions: List = None, - user_fields: List = None, - tweet_fields: List = None, - ) -> Streamlikessample10Response: - """ - Stream sampled Likes - Streams a 10% sample of public Likes in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Likes will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - like_with_tweet_author_fields: A comma separated list of LikeWithTweetAuthor fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - Streamlikessample10Response: Response data - """ - url = self.client.base_url + "/2/likes/sample10/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if like_with_tweet_author_fields is not None: - params["like_with_tweet_author.fields"] = ",".join( - str(item) for item in like_with_tweet_author_fields - ) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return Streamlikessample10Response.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/likes/models.py b/xdk/python/xdk/python/xdk/likes/models.py deleted file mode 100644 index 3bbcc1a4..00000000 --- a/xdk/python/xdk/python/xdk/likes/models.py +++ /dev/null @@ -1,103 +0,0 @@ -""" -Likes models for the X API. - -This module provides models for the Likes endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for streamLikesFirehose - - -class StreamlikesfirehoseResponse(BaseModel): - """Response model for streamLikesFirehose""" - - data: Optional["StreamlikesfirehoseResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreamlikesfirehoseResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreamlikesfirehoseResponseData(BaseModel): - """Nested model for StreamlikesfirehoseResponseData""" - - created_at: Optional[str] = None - id: Optional[str] = None - liked_tweet_id: Optional[str] = None - timestamp_ms: Optional[int] = None - tweet_author_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreamlikesfirehoseResponseIncludes(BaseModel): - """Nested model for StreamlikesfirehoseResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamLikesSample10 - - -class Streamlikessample10Response(BaseModel): - """Response model for streamLikesSample10""" - - data: Optional["Streamlikessample10ResponseData"] = None - errors: Optional[List] = None - includes: Optional["Streamlikessample10ResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streamlikessample10ResponseData(BaseModel): - """Nested model for Streamlikessample10ResponseData""" - - created_at: Optional[str] = None - id: Optional[str] = None - liked_tweet_id: Optional[str] = None - timestamp_ms: Optional[int] = None - tweet_author_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streamlikessample10ResponseIncludes(BaseModel): - """Nested model for Streamlikessample10ResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/python/xdk/lists/__init__.py b/xdk/python/xdk/python/xdk/lists/__init__.py deleted file mode 100644 index 8a25c7fb..00000000 --- a/xdk/python/xdk/python/xdk/lists/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Lists module for the X API. - -This module provides access to the Lists endpoints of the X API. -""" - -from .client import ListsClient - -__all__ = ["ListsClient"] diff --git a/xdk/python/xdk/python/xdk/lists/client.py b/xdk/python/xdk/python/xdk/lists/client.py deleted file mode 100644 index aa7c48fe..00000000 --- a/xdk/python/xdk/python/xdk/lists/client.py +++ /dev/null @@ -1,772 +0,0 @@ -""" -Lists client for the X API. - -This module provides a client for interacting with the Lists endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - UnfollowlistResponse, - UnpinlistResponse, - AddlistsmemberRequest, - AddlistsmemberResponse, - RemovelistsmemberbyuseridResponse, - GetusersfollowedlistsResponse, - FollowlistRequest, - FollowlistResponse, - CreatelistsRequest, - CreatelistsResponse, - GetlistsbyidResponse, - UpdatelistsRequest, - UpdatelistsResponse, - DeletelistsResponse, - GetuserspinnedlistsResponse, - PinlistRequest, - PinlistResponse, - GetuserslistmembershipsResponse, - GetusersownedlistsResponse, -) - - -class ListsClient: - """Client for Lists operations""" - - - def __init__(self, client: Client): - self.client = client - - - def unfollow_list( - self, - id: str, - list_id: str, - ) -> UnfollowlistResponse: - """ - Unfollow List - Causes the authenticated user to unfollow a specific List by its ID. - Args: - id: The ID of the authenticated source User that will unfollow the List. - Args: - list_id: The ID of the List to unfollow. - Returns: - UnfollowlistResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/followed_lists/{list_id}" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - url = url.replace("{list_id}", str(list_id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.delete( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.delete( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return UnfollowlistResponse.model_validate(response_data) - - - def unpin_list( - self, - id: str, - list_id: str, - ) -> UnpinlistResponse: - """ - Unpin List - Causes the authenticated user to unpin a specific List by its ID. - Args: - id: The ID of the authenticated source User for whom to return results. - Args: - list_id: The ID of the List to unpin. - Returns: - UnpinlistResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/pinned_lists/{list_id}" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - url = url.replace("{list_id}", str(list_id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.delete( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.delete( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return UnpinlistResponse.model_validate(response_data) - - - def add_lists_member( - self, - id: str, - body: Optional[AddlistsmemberRequest] = None, - ) -> AddlistsmemberResponse: - """ - Add List member - Adds a User to a specific List by its ID. - Args: - id: The ID of the List for which to add a member. - body: Request body - Returns: - AddlistsmemberResponse: Response data - """ - url = self.client.base_url + "/2/lists/{id}/members" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return AddlistsmemberResponse.model_validate(response_data) - - - def remove_lists_member_by_user_id( - self, - id: str, - user_id: str, - ) -> RemovelistsmemberbyuseridResponse: - """ - Remove List member - Removes a User from a specific List by its ID and the User’s ID. - Args: - id: The ID of the List to remove a member. - Args: - user_id: The ID of User that will be removed from the List. - Returns: - RemovelistsmemberbyuseridResponse: Response data - """ - url = self.client.base_url + "/2/lists/{id}/members/{user_id}" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - url = url.replace("{user_id}", str(user_id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.delete( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.delete( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return RemovelistsmemberbyuseridResponse.model_validate(response_data) - - - def get_users_followed_lists( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - list_fields: List = None, - expansions: List = None, - user_fields: List = None, - ) -> GetusersfollowedlistsResponse: - """ - Get followed Lists - Retrieves a list of Lists followed by a specific User by their ID. - Args: - id: The ID of the User to lookup. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - list_fields: A comma separated list of List fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Returns: - GetusersfollowedlistsResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/followed_lists" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if list_fields is not None: - params["list.fields"] = ",".join(str(item) for item in list_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetusersfollowedlistsResponse.model_validate(response_data) - - - def follow_list( - self, - id: str, - body: Optional[FollowlistRequest] = None, - ) -> FollowlistResponse: - """ - Follow List - Causes the authenticated user to follow a specific List by its ID. - Args: - id: The ID of the authenticated source User that will follow the List. - body: Request body - Returns: - FollowlistResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/followed_lists" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return FollowlistResponse.model_validate(response_data) - - - def create_lists( - self, - body: Optional[CreatelistsRequest] = None, - ) -> CreatelistsResponse: - """ - Create List - Creates a new List for the authenticated user. - body: Request body - Returns: - CreatelistsResponse: Response data - """ - url = self.client.base_url + "/2/lists" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return CreatelistsResponse.model_validate(response_data) - - - def get_lists_by_id( - self, - id: str, - list_fields: List = None, - expansions: List = None, - user_fields: List = None, - ) -> GetlistsbyidResponse: - """ - Get List by ID - Retrieves details of a specific List by its ID. - Args: - id: The ID of the List. - Args: - list_fields: A comma separated list of List fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Returns: - GetlistsbyidResponse: Response data - """ - url = self.client.base_url + "/2/lists/{id}" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if list_fields is not None: - params["list.fields"] = ",".join(str(item) for item in list_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetlistsbyidResponse.model_validate(response_data) - - - def update_lists( - self, - id: str, - body: Optional[UpdatelistsRequest] = None, - ) -> UpdatelistsResponse: - """ - Update List - Updates the details of a specific List owned by the authenticated user by its ID. - Args: - id: The ID of the List to modify. - body: Request body - Returns: - UpdatelistsResponse: Response data - """ - url = self.client.base_url + "/2/lists/{id}" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.put( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.put( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return UpdatelistsResponse.model_validate(response_data) - - - def delete_lists( - self, - id: str, - ) -> DeletelistsResponse: - """ - Delete List - Deletes a specific List owned by the authenticated user by its ID. - Args: - id: The ID of the List to delete. - Returns: - DeletelistsResponse: Response data - """ - url = self.client.base_url + "/2/lists/{id}" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.delete( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.delete( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return DeletelistsResponse.model_validate(response_data) - - - def get_users_pinned_lists( - self, - id: str, - list_fields: List = None, - expansions: List = None, - user_fields: List = None, - ) -> GetuserspinnedlistsResponse: - """ - Get pinned Lists - Retrieves a list of Lists pinned by the authenticated user. - Args: - id: The ID of the authenticated source User for whom to return results. - Args: - list_fields: A comma separated list of List fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Returns: - GetuserspinnedlistsResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/pinned_lists" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if list_fields is not None: - params["list.fields"] = ",".join(str(item) for item in list_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetuserspinnedlistsResponse.model_validate(response_data) - - - def pin_list( - self, - id: str, - body: PinlistRequest, - ) -> PinlistResponse: - """ - Pin List - Causes the authenticated user to pin a specific List by its ID. - Args: - id: The ID of the authenticated source User that will pin the List. - body: Request body - Returns: - PinlistResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/pinned_lists" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return PinlistResponse.model_validate(response_data) - - - def get_users_list_memberships( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - list_fields: List = None, - expansions: List = None, - user_fields: List = None, - ) -> GetuserslistmembershipsResponse: - """ - Get List memberships - Retrieves a list of Lists that a specific User is a member of by their ID. - Args: - id: The ID of the User to lookup. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - list_fields: A comma separated list of List fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Returns: - GetuserslistmembershipsResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/list_memberships" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if list_fields is not None: - params["list.fields"] = ",".join(str(item) for item in list_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetuserslistmembershipsResponse.model_validate(response_data) - - - def get_users_owned_lists( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - list_fields: List = None, - expansions: List = None, - user_fields: List = None, - ) -> GetusersownedlistsResponse: - """ - Get owned Lists - Retrieves a list of Lists owned by a specific User by their ID. - Args: - id: The ID of the User to lookup. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - list_fields: A comma separated list of List fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Returns: - GetusersownedlistsResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/owned_lists" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if list_fields is not None: - params["list.fields"] = ",".join(str(item) for item in list_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetusersownedlistsResponse.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/lists/models.py b/xdk/python/xdk/python/xdk/lists/models.py deleted file mode 100644 index 01886a12..00000000 --- a/xdk/python/xdk/python/xdk/lists/models.py +++ /dev/null @@ -1,539 +0,0 @@ -""" -Lists models for the X API. - -This module provides models for the Lists endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for unfollowList - - -class UnfollowlistResponse(BaseModel): - """Response model for unfollowList""" - - data: Optional["UnfollowlistResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class UnfollowlistResponseData(BaseModel): - """Nested model for UnfollowlistResponseData""" - - following: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for unpinList - - -class UnpinlistResponse(BaseModel): - """Response model for unpinList""" - - data: Optional["UnpinlistResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class UnpinlistResponseData(BaseModel): - """Nested model for UnpinlistResponseData""" - - pinned: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for addListsMember - - -class AddlistsmemberRequest(BaseModel): - """Request model for addListsMember""" - - user_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class AddlistsmemberResponse(BaseModel): - """Response model for addListsMember""" - - data: Optional["AddlistsmemberResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class AddlistsmemberResponseData(BaseModel): - """Nested model for AddlistsmemberResponseData""" - - is_member: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for removeListsMemberByUserId - - -class RemovelistsmemberbyuseridResponse(BaseModel): - """Response model for removeListsMemberByUserId""" - - data: Optional["RemovelistsmemberbyuseridResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class RemovelistsmemberbyuseridResponseData(BaseModel): - """Nested model for RemovelistsmemberbyuseridResponseData""" - - is_member: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersFollowedLists - - -class GetusersfollowedlistsResponse(BaseModel): - """Response model for getUsersFollowedLists""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetusersfollowedlistsResponseIncludes"] = None - meta: Optional["GetusersfollowedlistsResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersfollowedlistsResponseIncludes(BaseModel): - """Nested model for GetusersfollowedlistsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersfollowedlistsResponseMeta(BaseModel): - """Nested model for GetusersfollowedlistsResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for followList - - -class FollowlistRequest(BaseModel): - """Request model for followList""" - - list_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class FollowlistResponse(BaseModel): - """Response model for followList""" - - data: Optional["FollowlistResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class FollowlistResponseData(BaseModel): - """Nested model for FollowlistResponseData""" - - following: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for createLists - - -class CreatelistsRequest(BaseModel): - """Request model for createLists""" - - description: Optional[str] = None - name: Optional[str] = None - private: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatelistsResponse(BaseModel): - """Response model for createLists""" - - data: Optional["CreatelistsResponseData"] = Field( - description="A X List is a curated group of accounts.", default_factory=dict - ) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatelistsResponseData(BaseModel): - """Nested model for CreatelistsResponseData""" - - id: Optional[str] = None - name: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getListsById - - -class GetlistsbyidResponse(BaseModel): - """Response model for getListsById""" - - data: Optional["GetlistsbyidResponseData"] = Field( - description="A X List is a curated group of accounts.", default_factory=dict - ) - errors: Optional[List] = None - includes: Optional["GetlistsbyidResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetlistsbyidResponseData(BaseModel): - """Nested model for GetlistsbyidResponseData""" - - created_at: Optional[str] = None - description: Optional[str] = None - follower_count: Optional[int] = None - id: Optional[str] = None - member_count: Optional[int] = None - name: Optional[str] = None - owner_id: Optional[str] = None - private: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetlistsbyidResponseIncludes(BaseModel): - """Nested model for GetlistsbyidResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for updateLists - - -class UpdatelistsRequest(BaseModel): - """Request model for updateLists""" - - description: Optional[str] = None - name: Optional[str] = None - private: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class UpdatelistsResponse(BaseModel): - """Response model for updateLists""" - - data: Optional["UpdatelistsResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class UpdatelistsResponseData(BaseModel): - """Nested model for UpdatelistsResponseData""" - - updated: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for deleteLists - - -class DeletelistsResponse(BaseModel): - """Response model for deleteLists""" - - data: Optional["DeletelistsResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class DeletelistsResponseData(BaseModel): - """Nested model for DeletelistsResponseData""" - - deleted: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersPinnedLists - - -class GetuserspinnedlistsResponse(BaseModel): - """Response model for getUsersPinnedLists""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetuserspinnedlistsResponseIncludes"] = None - meta: Optional["GetuserspinnedlistsResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetuserspinnedlistsResponseIncludes(BaseModel): - """Nested model for GetuserspinnedlistsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetuserspinnedlistsResponseMeta(BaseModel): - """Nested model for GetuserspinnedlistsResponseMeta""" - - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for pinList - - -class PinlistRequest(BaseModel): - """Request model for pinList""" - - list_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class PinlistResponse(BaseModel): - """Response model for pinList""" - - data: Optional["PinlistResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class PinlistResponseData(BaseModel): - """Nested model for PinlistResponseData""" - - pinned: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersListMemberships - - -class GetuserslistmembershipsResponse(BaseModel): - """Response model for getUsersListMemberships""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetuserslistmembershipsResponseIncludes"] = None - meta: Optional["GetuserslistmembershipsResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetuserslistmembershipsResponseIncludes(BaseModel): - """Nested model for GetuserslistmembershipsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetuserslistmembershipsResponseMeta(BaseModel): - """Nested model for GetuserslistmembershipsResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersOwnedLists - - -class GetusersownedlistsResponse(BaseModel): - """Response model for getUsersOwnedLists""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetusersownedlistsResponseIncludes"] = None - meta: Optional["GetusersownedlistsResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersownedlistsResponseIncludes(BaseModel): - """Nested model for GetusersownedlistsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersownedlistsResponseMeta(BaseModel): - """Nested model for GetusersownedlistsResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/python/xdk/media/__init__.py b/xdk/python/xdk/python/xdk/media/__init__.py deleted file mode 100644 index 74910c78..00000000 --- a/xdk/python/xdk/python/xdk/media/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Media module for the X API. - -This module provides access to the Media endpoints of the X API. -""" - -from .client import MediaClient - -__all__ = ["MediaClient"] diff --git a/xdk/python/xdk/python/xdk/media/client.py b/xdk/python/xdk/python/xdk/media/client.py deleted file mode 100644 index 7203f116..00000000 --- a/xdk/python/xdk/python/xdk/media/client.py +++ /dev/null @@ -1,554 +0,0 @@ -""" -Media client for the X API. - -This module provides a client for interacting with the Media endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - CreatemediasubtitlesRequest, - CreatemediasubtitlesResponse, - DeletemediasubtitlesRequest, - DeletemediasubtitlesResponse, - FinalizemediauploadResponse, - GetmediabymediakeyResponse, - GetmediabymediakeysResponse, - InitializemediauploadRequest, - InitializemediauploadResponse, - GetmediauploadstatusResponse, - MediauploadRequest, - MediauploadResponse, - GetmediaanalyticsResponse, - CreatemediametadataRequest, - CreatemediametadataResponse, - AppendmediauploadRequest, - AppendmediauploadResponse, -) - - -class MediaClient: - """Client for Media operations""" - - - def __init__(self, client: Client): - self.client = client - - - def create_media_subtitles( - self, - body: Optional[CreatemediasubtitlesRequest] = None, - ) -> CreatemediasubtitlesResponse: - """ - Create Media subtitles - Creates subtitles for a specific Media file. - body: Request body - Returns: - CreatemediasubtitlesResponse: Response data - """ - url = self.client.base_url + "/2/media/subtitles" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return CreatemediasubtitlesResponse.model_validate(response_data) - - - def delete_media_subtitles( - self, - body: Optional[DeletemediasubtitlesRequest] = None, - ) -> DeletemediasubtitlesResponse: - """ - Delete Media subtitles - Deletes subtitles for a specific Media file. - body: Request body - Returns: - DeletemediasubtitlesResponse: Response data - """ - url = self.client.base_url + "/2/media/subtitles" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.delete( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.delete( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return DeletemediasubtitlesResponse.model_validate(response_data) - - - def finalize_media_upload( - self, - id: str, - ) -> FinalizemediauploadResponse: - """ - Finalize Media upload - Finalizes a Media upload request. - Args: - id: The media id of the targeted media to finalize. - Returns: - FinalizemediauploadResponse: Response data - """ - url = self.client.base_url + "/2/media/upload/{id}/finalize" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return FinalizemediauploadResponse.model_validate(response_data) - - - def get_media_by_media_key( - self, - media_key: str, - media_fields: List = None, - ) -> GetmediabymediakeyResponse: - """ - Get Media by media key - Retrieves details of a specific Media file by its media key. - Args: - media_key: A single Media Key. - Args: - media_fields: A comma separated list of Media fields to display. - Returns: - GetmediabymediakeyResponse: Response data - """ - url = self.client.base_url + "/2/media/{media_key}" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - url = url.replace("{media_key}", str(media_key)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetmediabymediakeyResponse.model_validate(response_data) - - - def get_media_by_media_keys( - self, - media_keys: List, - media_fields: List = None, - ) -> GetmediabymediakeysResponse: - """ - Get Media by media keys - Retrieves details of Media files by their media keys. - Args: - media_keys: A comma separated list of Media Keys. Up to 100 are allowed in a single request. - Args: - media_fields: A comma separated list of Media fields to display. - Returns: - GetmediabymediakeysResponse: Response data - """ - url = self.client.base_url + "/2/media" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if media_keys is not None: - params["media_keys"] = ",".join(str(item) for item in media_keys) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetmediabymediakeysResponse.model_validate(response_data) - - - def initialize_media_upload( - self, - body: Optional[InitializemediauploadRequest] = None, - ) -> InitializemediauploadResponse: - """ - Initialize media upload - Initializes a media upload. - body: Request body - Returns: - InitializemediauploadResponse: Response data - """ - url = self.client.base_url + "/2/media/upload/initialize" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return InitializemediauploadResponse.model_validate(response_data) - - - def get_media_upload_status( - self, - media_id: str, - command: str = None, - ) -> GetmediauploadstatusResponse: - """ - Get Media upload status - Retrieves the status of a Media upload by its ID. - Args: - media_id: Media id for the requested media upload status. - Args: - command: The command for the media upload request. - Returns: - GetmediauploadstatusResponse: Response data - """ - url = self.client.base_url + "/2/media/upload" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if media_id is not None: - params["media_id"] = media_id - if command is not None: - params["command"] = command - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetmediauploadstatusResponse.model_validate(response_data) - - - def media_upload( - self, - body: Optional[MediauploadRequest] = None, - ) -> MediauploadResponse: - """ - Upload media - Uploads a media file for use in posts or other content. - body: Request body - Returns: - MediauploadResponse: Response data - """ - url = self.client.base_url + "/2/media/upload" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return MediauploadResponse.model_validate(response_data) - - - def get_media_analytics( - self, - media_keys: List, - end_time: str, - start_time: str, - granularity: str, - media_analytics_fields: List = None, - ) -> GetmediaanalyticsResponse: - """ - Get Media analytics - Retrieves analytics data for media. - Args: - media_keys: A comma separated list of Media Keys. Up to 100 are allowed in a single request. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range. - Args: - granularity: The granularity for the search counts results. - Args: - media_analytics_fields: A comma separated list of MediaAnalytics fields to display. - Returns: - GetmediaanalyticsResponse: Response data - """ - url = self.client.base_url + "/2/media/analytics" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if media_keys is not None: - params["media_keys"] = ",".join(str(item) for item in media_keys) - if end_time is not None: - params["end_time"] = end_time - if start_time is not None: - params["start_time"] = start_time - if granularity is not None: - params["granularity"] = granularity - if media_analytics_fields is not None: - params["media_analytics.fields"] = ",".join( - str(item) for item in media_analytics_fields - ) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetmediaanalyticsResponse.model_validate(response_data) - - - def create_media_metadata( - self, - body: Optional[CreatemediametadataRequest] = None, - ) -> CreatemediametadataResponse: - """ - Create Media metadata - Creates metadata for a Media file. - body: Request body - Returns: - CreatemediametadataResponse: Response data - """ - url = self.client.base_url + "/2/media/metadata" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return CreatemediametadataResponse.model_validate(response_data) - - - def append_media_upload( - self, - id: str, - body: Optional[AppendmediauploadRequest] = None, - ) -> AppendmediauploadResponse: - """ - Append Media upload - Appends data to a Media upload request. - Args: - id: The media identifier for the media to perform the append operation. - body: Request body - Returns: - AppendmediauploadResponse: Response data - """ - url = self.client.base_url + "/2/media/upload/{id}/append" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return AppendmediauploadResponse.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/media/models.py b/xdk/python/xdk/python/xdk/media/models.py deleted file mode 100644 index df453dbe..00000000 --- a/xdk/python/xdk/python/xdk/media/models.py +++ /dev/null @@ -1,822 +0,0 @@ -""" -Media models for the X API. - -This module provides models for the Media endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for createMediaSubtitles - - -class CreatemediasubtitlesRequest(BaseModel): - """Request model for createMediaSubtitles""" - - id: Optional[str] = None - media_category: Optional[str] = None - subtitles: Optional["CreatemediasubtitlesRequestSubtitles"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediasubtitlesResponse(BaseModel): - """Response model for createMediaSubtitles""" - - data: Optional["CreatemediasubtitlesResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediasubtitlesRequestSubtitles(BaseModel): - """Nested model for CreatemediasubtitlesRequestSubtitles""" - - display_name: Optional[str] = None - id: Optional[str] = None - language_code: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediasubtitlesResponseData(BaseModel): - """Nested model for CreatemediasubtitlesResponseData""" - - associated_subtitles: Optional[List] = None - id: Optional[str] = None - media_category: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for deleteMediaSubtitles - - -class DeletemediasubtitlesRequest(BaseModel): - """Request model for deleteMediaSubtitles""" - - id: Optional[str] = None - language_code: Optional[str] = None - media_category: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class DeletemediasubtitlesResponse(BaseModel): - """Response model for deleteMediaSubtitles""" - - data: Optional["DeletemediasubtitlesResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class DeletemediasubtitlesResponseData(BaseModel): - """Nested model for DeletemediasubtitlesResponseData""" - - deleted: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for finalizeMediaUpload - - -class FinalizemediauploadResponse(BaseModel): - """Response model for finalizeMediaUpload""" - - data: Optional["FinalizemediauploadResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class FinalizemediauploadResponseData(BaseModel): - """Nested model for FinalizemediauploadResponseData""" - - expires_after_secs: Optional[int] = None - id: Optional[str] = None - media_key: Optional[str] = None - processing_info: Optional["FinalizemediauploadResponseDataProcessingInfo"] = None - size: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class FinalizemediauploadResponseDataProcessingInfo(BaseModel): - """Nested model for FinalizemediauploadResponseDataProcessingInfo""" - - check_after_secs: Optional[int] = None - progress_percent: Optional[int] = None - state: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getMediaByMediaKey - - -class GetmediabymediakeyResponse(BaseModel): - """Response model for getMediaByMediaKey""" - - data: Optional["GetmediabymediakeyResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetmediabymediakeyResponseData(BaseModel): - """Nested model for GetmediabymediakeyResponseData""" - - height: Optional[int] = None - media_key: Optional[str] = None - type: Optional[str] = None - width: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getMediaByMediaKeys - - -class GetmediabymediakeysResponse(BaseModel): - """Response model for getMediaByMediaKeys""" - - data: Optional[List] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for initializeMediaUpload - - -class InitializemediauploadRequest(BaseModel): - """Request model for initializeMediaUpload""" - - additional_owners: Optional[List] = None - media_category: Optional[str] = None - media_type: Optional[str] = None - shared: Optional[bool] = None - total_bytes: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class InitializemediauploadResponse(BaseModel): - """Response model for initializeMediaUpload""" - - data: Optional["InitializemediauploadResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class InitializemediauploadResponseData(BaseModel): - """Nested model for InitializemediauploadResponseData""" - - expires_after_secs: Optional[int] = None - id: Optional[str] = None - media_key: Optional[str] = None - processing_info: Optional["InitializemediauploadResponseDataProcessingInfo"] = None - size: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class InitializemediauploadResponseDataProcessingInfo(BaseModel): - """Nested model for InitializemediauploadResponseDataProcessingInfo""" - - check_after_secs: Optional[int] = None - progress_percent: Optional[int] = None - state: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getMediaUploadStatus - - -class GetmediauploadstatusResponse(BaseModel): - """Response model for getMediaUploadStatus""" - - data: Optional["GetmediauploadstatusResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetmediauploadstatusResponseData(BaseModel): - """Nested model for GetmediauploadstatusResponseData""" - - expires_after_secs: Optional[int] = None - id: Optional[str] = None - media_key: Optional[str] = None - processing_info: Optional["GetmediauploadstatusResponseDataProcessingInfo"] = None - size: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetmediauploadstatusResponseDataProcessingInfo(BaseModel): - """Nested model for GetmediauploadstatusResponseDataProcessingInfo""" - - check_after_secs: Optional[int] = None - progress_percent: Optional[int] = None - state: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for mediaUpload - - -class MediauploadRequest(BaseModel): - """Request model for mediaUpload""" - - additional_owners: Optional[List] = None - media: Any = None - media_category: Optional[str] = None - media_type: Optional[str] = None - shared: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class MediauploadResponse(BaseModel): - """Response model for mediaUpload""" - - data: Optional["MediauploadResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class MediauploadResponseData(BaseModel): - """Nested model for MediauploadResponseData""" - - expires_after_secs: Optional[int] = None - id: Optional[str] = None - media_key: Optional[str] = None - processing_info: Optional["MediauploadResponseDataProcessingInfo"] = None - size: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class MediauploadResponseDataProcessingInfo(BaseModel): - """Nested model for MediauploadResponseDataProcessingInfo""" - - check_after_secs: Optional[int] = None - progress_percent: Optional[int] = None - state: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getMediaAnalytics - - -class GetmediaanalyticsResponse(BaseModel): - """Response model for getMediaAnalytics""" - - data: Optional[List] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for createMediaMetadata - - -class CreatemediametadataRequest(BaseModel): - """Request model for createMediaMetadata""" - - id: Optional[str] = None - metadata: Optional["CreatemediametadataRequestMetadata"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataResponse(BaseModel): - """Response model for createMediaMetadata""" - - data: Optional["CreatemediametadataResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataRequestMetadata(BaseModel): - """Nested model for CreatemediametadataRequestMetadata""" - - allow_download_status: Optional[ - "CreatemediametadataRequestMetadataAllowDownloadStatus" - ] = None - alt_text: Optional["CreatemediametadataRequestMetadataAltText"] = None - audience_policy: Optional["CreatemediametadataRequestMetadataAudiencePolicy"] = None - content_expiration: Optional[ - "CreatemediametadataRequestMetadataContentExpiration" - ] = None - domain_restrictions: Optional[ - "CreatemediametadataRequestMetadataDomainRestrictions" - ] = None - found_media_origin: Optional[ - "CreatemediametadataRequestMetadataFoundMediaOrigin" - ] = None - geo_restrictions: Any = None - management_info: Optional["CreatemediametadataRequestMetadataManagementInfo"] = None - preview_image: Optional["CreatemediametadataRequestMetadataPreviewImage"] = None - sensitive_media_warning: Optional[ - "CreatemediametadataRequestMetadataSensitiveMediaWarning" - ] = None - shared_info: Optional["CreatemediametadataRequestMetadataSharedInfo"] = None - sticker_info: Optional["CreatemediametadataRequestMetadataStickerInfo"] = None - upload_source: Optional["CreatemediametadataRequestMetadataUploadSource"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataRequestMetadataAllowDownloadStatus(BaseModel): - """Nested model for CreatemediametadataRequestMetadataAllowDownloadStatus""" - - allow_download: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataRequestMetadataAltText(BaseModel): - """Nested model for CreatemediametadataRequestMetadataAltText""" - - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataRequestMetadataAudiencePolicy(BaseModel): - """Nested model for CreatemediametadataRequestMetadataAudiencePolicy""" - - creator_subscriptions: Optional[List] = None - x_subscriptions: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataRequestMetadataContentExpiration(BaseModel): - """Nested model for CreatemediametadataRequestMetadataContentExpiration""" - - timestamp_sec: Optional[float] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataRequestMetadataDomainRestrictions(BaseModel): - """Nested model for CreatemediametadataRequestMetadataDomainRestrictions""" - - whitelist: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataRequestMetadataFoundMediaOrigin(BaseModel): - """Nested model for CreatemediametadataRequestMetadataFoundMediaOrigin""" - - id: Optional[str] = None - provider: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataRequestMetadataManagementInfo(BaseModel): - """Nested model for CreatemediametadataRequestMetadataManagementInfo""" - - managed: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataRequestMetadataPreviewImage(BaseModel): - """Nested model for CreatemediametadataRequestMetadataPreviewImage""" - - media_key: Optional["CreatemediametadataRequestMetadataPreviewImageMediaKey"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataRequestMetadataPreviewImageMediaKey(BaseModel): - """Nested model for CreatemediametadataRequestMetadataPreviewImageMediaKey""" - - media: Optional[str] = None - media_category: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataRequestMetadataSensitiveMediaWarning(BaseModel): - """Nested model for CreatemediametadataRequestMetadataSensitiveMediaWarning""" - - adult_content: Optional[bool] = None - graphic_violence: Optional[bool] = None - other: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataRequestMetadataSharedInfo(BaseModel): - """Nested model for CreatemediametadataRequestMetadataSharedInfo""" - - shared: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataRequestMetadataStickerInfo(BaseModel): - """Nested model for CreatemediametadataRequestMetadataStickerInfo""" - - stickers: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataRequestMetadataUploadSource(BaseModel): - """Nested model for CreatemediametadataRequestMetadataUploadSource""" - - upload_source: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataResponseData(BaseModel): - """Nested model for CreatemediametadataResponseData""" - - associated_metadata: Optional[ - "CreatemediametadataResponseDataAssociatedMetadata" - ] = None - id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataResponseDataAssociatedMetadata(BaseModel): - """Nested model for CreatemediametadataResponseDataAssociatedMetadata""" - - allow_download_status: Optional[ - "CreatemediametadataResponseDataAssociatedMetadataAllowDownloadStatus" - ] = None - alt_text: Optional["CreatemediametadataResponseDataAssociatedMetadataAltText"] = ( - None - ) - audience_policy: Optional[ - "CreatemediametadataResponseDataAssociatedMetadataAudiencePolicy" - ] = None - content_expiration: Optional[ - "CreatemediametadataResponseDataAssociatedMetadataContentExpiration" - ] = None - domain_restrictions: Optional[ - "CreatemediametadataResponseDataAssociatedMetadataDomainRestrictions" - ] = None - found_media_origin: Optional[ - "CreatemediametadataResponseDataAssociatedMetadataFoundMediaOrigin" - ] = None - geo_restrictions: Any = None - management_info: Optional[ - "CreatemediametadataResponseDataAssociatedMetadataManagementInfo" - ] = None - preview_image: Optional[ - "CreatemediametadataResponseDataAssociatedMetadataPreviewImage" - ] = None - sensitive_media_warning: Optional[ - "CreatemediametadataResponseDataAssociatedMetadataSensitiveMediaWarning" - ] = None - shared_info: Optional[ - "CreatemediametadataResponseDataAssociatedMetadataSharedInfo" - ] = None - sticker_info: Optional[ - "CreatemediametadataResponseDataAssociatedMetadataStickerInfo" - ] = None - upload_source: Optional[ - "CreatemediametadataResponseDataAssociatedMetadataUploadSource" - ] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataResponseDataAssociatedMetadataAllowDownloadStatus(BaseModel): - """Nested model for CreatemediametadataResponseDataAssociatedMetadataAllowDownloadStatus""" - - allow_download: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataResponseDataAssociatedMetadataAltText(BaseModel): - """Nested model for CreatemediametadataResponseDataAssociatedMetadataAltText""" - - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataResponseDataAssociatedMetadataAudiencePolicy(BaseModel): - """Nested model for CreatemediametadataResponseDataAssociatedMetadataAudiencePolicy""" - - creator_subscriptions: Optional[List] = None - x_subscriptions: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataResponseDataAssociatedMetadataContentExpiration(BaseModel): - """Nested model for CreatemediametadataResponseDataAssociatedMetadataContentExpiration""" - - timestamp_sec: Optional[float] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataResponseDataAssociatedMetadataDomainRestrictions(BaseModel): - """Nested model for CreatemediametadataResponseDataAssociatedMetadataDomainRestrictions""" - - whitelist: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataResponseDataAssociatedMetadataFoundMediaOrigin(BaseModel): - """Nested model for CreatemediametadataResponseDataAssociatedMetadataFoundMediaOrigin""" - - id: Optional[str] = None - provider: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataResponseDataAssociatedMetadataManagementInfo(BaseModel): - """Nested model for CreatemediametadataResponseDataAssociatedMetadataManagementInfo""" - - managed: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataResponseDataAssociatedMetadataPreviewImage(BaseModel): - """Nested model for CreatemediametadataResponseDataAssociatedMetadataPreviewImage""" - - media_key: Optional[ - "CreatemediametadataResponseDataAssociatedMetadataPreviewImageMediaKey" - ] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataResponseDataAssociatedMetadataPreviewImageMediaKey(BaseModel): - """Nested model for CreatemediametadataResponseDataAssociatedMetadataPreviewImageMediaKey""" - - media: Optional[str] = None - media_category: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataResponseDataAssociatedMetadataSensitiveMediaWarning(BaseModel): - """Nested model for CreatemediametadataResponseDataAssociatedMetadataSensitiveMediaWarning""" - - adult_content: Optional[bool] = None - graphic_violence: Optional[bool] = None - other: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataResponseDataAssociatedMetadataSharedInfo(BaseModel): - """Nested model for CreatemediametadataResponseDataAssociatedMetadataSharedInfo""" - - shared: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataResponseDataAssociatedMetadataStickerInfo(BaseModel): - """Nested model for CreatemediametadataResponseDataAssociatedMetadataStickerInfo""" - - stickers: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatemediametadataResponseDataAssociatedMetadataUploadSource(BaseModel): - """Nested model for CreatemediametadataResponseDataAssociatedMetadataUploadSource""" - - upload_source: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for appendMediaUpload - - -class AppendmediauploadRequest(BaseModel): - """Request model for appendMediaUpload""" - - media: Optional[str] = Field(default=None, description="The file to upload.") - segment_index: Optional[Any] = Field(default=None) - media: Optional[str] = Field(default=None, description="The file to upload.") - segment_index: Optional[Any] = Field(default=None) - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class AppendmediauploadResponse(BaseModel): - """Response model for appendMediaUpload""" - - data: Optional["AppendmediauploadResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class AppendmediauploadResponseData(BaseModel): - """Nested model for AppendmediauploadResponseData""" - - expires_at: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/python/xdk/oauth2_auth.py b/xdk/python/xdk/python/xdk/oauth2_auth.py deleted file mode 100644 index 852baae7..00000000 --- a/xdk/python/xdk/python/xdk/oauth2_auth.py +++ /dev/null @@ -1,158 +0,0 @@ -""" -OAuth2 PKCE authentication for the X API. - -This module provides OAuth2 PKCE authentication functionality for the X API client. -""" - -import secrets -import base64 -import hashlib -import time -import urllib.parse -from typing import Dict, Optional, Any, Tuple -from requests_oauthlib import OAuth2Session - - -class OAuth2PKCEAuth: - """OAuth2 PKCE authentication for the X API.""" - - - def __init__( - self, - base_url: str = "https://api.twitter.com", - client_id: str = None, - client_secret: str = None, - redirect_uri: str = None, - token: Dict[str, Any] = None, - scope: str = None, - ): - """Initialize the OAuth2 PKCE authentication. - Args: - base_url: The base URL for the X API. - client_id: The client ID for the X API. - client_secret: The client secret for the X API. - redirect_uri: The redirect URI for OAuth2 authorization. - token: An existing OAuth2 token dictionary (if available). - scope: Space-separated list of scopes for OAuth2 authorization. - """ - self.base_url = base_url - self.client_id = client_id - self.client_secret = client_secret - self.redirect_uri = redirect_uri - self.token = token - self.scope = scope - self.oauth2_session = None - self.code_verifier = None - self.code_challenge = None - # Set up OAuth2 session if we have a token - if token and client_id: - self._setup_oauth_session() - - - def _setup_oauth_session(self): - """Set up the OAuth2 session with existing token.""" - self.oauth2_session = OAuth2Session( - client_id=self.client_id, - token=self.token, - redirect_uri=self.redirect_uri, - scope=self.scope, - ) - - - def _generate_code_verifier(self, length: int = 128) -> str: - """Generate a code verifier for PKCE. - Args: - length: The length of the code verifier. - Returns: - str: The generated code verifier. - """ - code_verifier = secrets.token_urlsafe(96)[:length] - return code_verifier - - - def _generate_code_challenge(self, code_verifier: str) -> str: - """Generate a code challenge from the code verifier. - Args: - code_verifier: The code verifier to generate a challenge from. - Returns: - str: The generated code challenge. - """ - code_challenge = hashlib.sha256(code_verifier.encode()).digest() - code_challenge = base64.urlsafe_b64encode(code_challenge).decode().rstrip("=") - return code_challenge - - - def get_authorization_url(self) -> Tuple[str, str]: - """Get the authorization URL for the OAuth2 PKCE flow. - Returns: - tuple: (authorization_url, state) - """ - self.code_verifier = self._generate_code_verifier() - self.code_challenge = self._generate_code_challenge(self.code_verifier) - self.oauth2_session = OAuth2Session( - client_id=self.client_id, redirect_uri=self.redirect_uri, scope=self.scope - ) - auth_url, state = self.oauth2_session.authorization_url( - f"{self.base_url}/oauth2/authorize", - code_challenge=self.code_challenge, - code_challenge_method="S256", - ) - return auth_url, state - - - def fetch_token(self, authorization_response: str) -> Dict[str, Any]: - """Fetch token using authorization response and code verifier. - Args: - authorization_response: The full callback URL received after authorization - Returns: - Dict[str, Any]: The token dictionary - """ - if not self.oauth2_session: - raise ValueError( - "OAuth2 session not initialized. Call get_authorization_url first." - ) - self.token = self.oauth2_session.fetch_token( - f"{self.base_url}/oauth2/token", - authorization_response=authorization_response, - code_verifier=self.code_verifier, - client_id=self.client_id, - include_client_id=True, - ) - return self.token - - - def refresh_token(self) -> Dict[str, Any]: - """Refresh the access token. - Returns: - Dict[str, Any]: The refreshed token dictionary - """ - if not self.oauth2_session or not self.token: - raise ValueError("No token to refresh") - refresh_url = f"{self.base_url}/oauth2/token" - self.token = self.oauth2_session.refresh_token( - refresh_url, client_id=self.client_id, client_secret=self.client_secret - ) - return self.token - - @property - - - def access_token(self) -> Optional[str]: - """Get the current access token. - Returns: - Optional[str]: The current access token, or None if no token exists. - """ - if self.token: - return self.token.get("access_token") - return None - - - def is_token_expired(self) -> bool: - """Check if the token is expired. - Returns: - bool: True if the token is expired, False otherwise. - """ - if not self.token or "expires_at" not in self.token: - return True - # Add a 10-second buffer to avoid edge cases - return time.time() > (self.token["expires_at"] - 10) diff --git a/xdk/python/xdk/python/xdk/paginator.py b/xdk/python/xdk/python/xdk/paginator.py deleted file mode 100644 index 3af61744..00000000 --- a/xdk/python/xdk/python/xdk/paginator.py +++ /dev/null @@ -1,277 +0,0 @@ -""" -Cursor-based pagination utilities for the X API SDK. - -This module provides a Cursor for elegant pagination support. -""" - -from typing import ( - Iterator, - Any, - Optional, - Callable, - TypeVar, - Generic, - overload, - Protocol, - runtime_checkable, -) -import inspect - -# Type variable for response type -ResponseType = TypeVar("ResponseType") - - -@runtime_checkable -class PaginatableMethod(Protocol[ResponseType]): - """ - Protocol for methods that support pagination. - - A method is considered paginatable if it accepts pagination_token - and/or max_results parameters. - """ - - - def __call__( - self, - *args, - pagination_token: Optional[str] = None, - max_results: Optional[int] = None, - **kwargs, - ) -> ResponseType: ... - - -class PaginationError(TypeError): - """Raised when a non-paginatable method is passed to Cursor.""" - - pass - - -def _validate_paginatable_method(method: Callable) -> None: - """ - Validate that a method supports pagination parameters. - Raises PaginationError if the method doesn't support pagination. - """ - sig = inspect.signature(method) - params = sig.parameters - # Check if method has pagination_token, next_token, or max_results parameters - has_pagination_token = "pagination_token" in params - has_next_token = "next_token" in params - has_max_results = "max_results" in params - if not (has_pagination_token or has_next_token or has_max_results): - raise PaginationError( - f"Method '{method.__name__}' does not support pagination. " - f"Paginatable methods must accept 'pagination_token', 'next_token', and/or 'max_results' parameters. " - f"Available parameters: {list(params.keys())}" - ) - - -class Cursor(Generic[ResponseType]): - """ - A cursor for handling pagination in API calls. - - This class wraps any API method and provides elegant pagination - through .items() and .pages() methods. The cursor preserves the - return type of the wrapped method for proper type hints. - - Example usage: - # For methods requiring arguments - cursor = Cursor(client.users.get_users_blocking, "user_id", max_results=100) - for user in cursor.items(250): # user is properly typed - print(user.name) - - # For methods with query parameters - cursor = Cursor(client.tweets.search_posts_recent, "python", max_results=50) - for page in cursor.pages(5): # page is SearchResponse type - print(f"Got {len(page.data)} tweets") - """ - - - def __init__( - self, method: PaginatableMethod[ResponseType], *args: Any, **kwargs: Any - ): - """ - Initialize the cursor. - Args: - method: The API method to call for each page (must support pagination) - *args: Positional arguments to pass to the API method - **kwargs: Keyword arguments to pass to the API method (excluding pagination params) - Raises: - PaginationError: If the method doesn't support pagination parameters - """ - # Validate method supports pagination at runtime - _validate_paginatable_method(method) - self.method = method - self.args = args - self.params = kwargs.copy() - - - def items(self, limit: Optional[int] = None) -> Iterator[Any]: - """ - Iterate over individual items from paginated responses. - Args: - limit: Maximum number of items to return (None for unlimited) - Yields: - Individual items from the API responses - """ - return _ItemIterator(self, limit) - - - def pages(self, limit: Optional[int] = None) -> Iterator[ResponseType]: - """ - Iterate over pages of responses. - Args: - limit: Maximum number of pages to return (None for unlimited) - Yields: - Page responses from the API (same type as the wrapped method returns) - """ - return _PageIterator(self, limit) - - -# Factory function for better type inference - - -@overload - - -def cursor( - method: PaginatableMethod[ResponseType], *args: Any, **kwargs: Any -) -> Cursor[ResponseType]: ... - - -def cursor( - method: PaginatableMethod[ResponseType], *args: Any, **kwargs: Any -) -> Cursor[ResponseType]: - """ - Create a cursor with proper type inference and validation. - This factory function helps with type inference so you get proper - type hints for the response type, and validates that the method - supports pagination at both static analysis and runtime. - Args: - method: The API method to wrap (must support pagination) - *args: Positional arguments to pass to the method - **kwargs: Keyword arguments to pass to the method - Returns: - A properly typed Cursor instance - Raises: - PaginationError: If the method doesn't support pagination parameters - Example: - # Type is inferred as Cursor[GetUsersResponse] - users_cursor = cursor(client.users.get_users_blocking, "user_id", max_results=100) - # page is typed as GetUsersResponse - for page in users_cursor.pages(5): - print(len(page.data)) - # For search methods - search_cursor = cursor(client.tweets.search_posts_recent, "python", max_results=50) - for tweet in search_cursor.items(100): - print(tweet.text) - """ - return Cursor(method, *args, **kwargs) - - -class _PageIterator(Generic[ResponseType], Iterator[ResponseType]): - """Internal iterator for pages.""" - - - def __init__(self, cursor: Cursor[ResponseType], limit: Optional[int]): - self.cursor = cursor - self.limit = limit - self.count = 0 - self.exhausted = False - self._next_token: Optional[str] = None - - - def __iter__(self) -> Iterator[ResponseType]: - return self - - - def __next__(self) -> ResponseType: - if self.exhausted or (self.limit is not None and self.count >= self.limit): - raise StopIteration - # Prepare params for this request - params = self.cursor.params.copy() - if self._next_token: - # Try different pagination parameter names - if self._supports_pagination_token(): - params["pagination_token"] = self._next_token - elif self._supports_next_token(): - params["next_token"] = self._next_token - # Make the API call with both positional and keyword arguments - response = self.cursor.method(*self.cursor.args, **params) - # Extract next token - self._next_token = self._extract_next_token(response) - # Check if we're done - if not self._next_token: - self.exhausted = True - self.count += 1 - return response - - - def _supports_pagination_token(self) -> bool: - """Check if the method supports pagination_token parameter.""" - sig = inspect.signature(self.cursor.method) - return "pagination_token" in sig.parameters - - - def _supports_next_token(self) -> bool: - """Check if the method supports next_token parameter.""" - sig = inspect.signature(self.cursor.method) - return "next_token" in sig.parameters - - - def _extract_next_token(self, response: ResponseType) -> Optional[str]: - """Extract the next_token from the response.""" - # Try common patterns for next_token - if hasattr(response, "meta") and response.meta: - if hasattr(response.meta, "next_token"): - return response.meta.next_token - return None - - -class _ItemIterator(Iterator[Any]): - """Internal iterator for individual items.""" - - - def __init__(self, cursor: Cursor, limit: Optional[int]): - self.page_iterator = _PageIterator(cursor, None) # No page limit for items - self.limit = limit - self.count = 0 - self._current_items = [] - self._current_index = 0 - - - def __iter__(self) -> Iterator[Any]: - return self - - - def __next__(self) -> Any: - if self.limit is not None and self.count >= self.limit: - raise StopIteration - # If we've exhausted current items, get next page - while self._current_index >= len(self._current_items): - try: - page = next(self.page_iterator) - # Try common patterns for data arrays - items = self._extract_items(page) - self._current_items = items or [] - self._current_index = 0 - # If the page has no items, continue to next page - if not self._current_items: - continue - except StopIteration: - raise StopIteration - # Return current item and advance - item = self._current_items[self._current_index] - self._current_index += 1 - self.count += 1 - return item - - - def _extract_items(self, response: Any) -> Optional[list]: - """Extract items from response, trying common field names.""" - # Try common field names for data arrays - for field_name in ["data", "results", "items"]: - if hasattr(response, field_name): - items = getattr(response, field_name) - if isinstance(items, list): - return items - return None diff --git a/xdk/python/xdk/python/xdk/spaces/__init__.py b/xdk/python/xdk/python/xdk/spaces/__init__.py deleted file mode 100644 index 840cbb01..00000000 --- a/xdk/python/xdk/python/xdk/spaces/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Spaces module for the X API. - -This module provides access to the Spaces endpoints of the X API. -""" - -from .client import SpacesClient - -__all__ = ["SpacesClient"] diff --git a/xdk/python/xdk/python/xdk/spaces/client.py b/xdk/python/xdk/python/xdk/spaces/client.py deleted file mode 100644 index ca62d3e2..00000000 --- a/xdk/python/xdk/python/xdk/spaces/client.py +++ /dev/null @@ -1,439 +0,0 @@ -""" -Spaces client for the X API. - -This module provides a client for interacting with the Spaces endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - GetspacespostsResponse, - SearchspacesResponse, - GetspacesbycreatoridsResponse, - GetspacesbuyersResponse, - GetspacesbyidsResponse, - GetspacesbyidResponse, -) - - -class SpacesClient: - """Client for Spaces operations""" - - - def __init__(self, client: Client): - self.client = client - - - def get_spaces_posts( - self, - id: str, - max_results: int = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetspacespostsResponse: - """ - Get Space Posts - Retrieves a list of Posts shared in a specific Space by its ID. - Args: - id: The ID of the Space to be retrieved. - Args: - max_results: The number of Posts to fetch from the provided space. If not provided, the value will default to the maximum of 100. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetspacespostsResponse: Response data - """ - url = self.client.base_url + "/2/spaces/{id}/tweets" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetspacespostsResponse.model_validate(response_data) - - - def search_spaces( - self, - query: str, - state: str = None, - max_results: int = None, - space_fields: List = None, - expansions: List = None, - user_fields: List = None, - topic_fields: List = None, - ) -> SearchspacesResponse: - """ - Search Spaces - Retrieves a list of Spaces matching the specified search query. - Args: - query: The search query. - Args: - state: The state of Spaces to search for. - Args: - max_results: The number of results to return. - Args: - space_fields: A comma separated list of Space fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Args: - topic_fields: A comma separated list of Topic fields to display. - Returns: - SearchspacesResponse: Response data - """ - url = self.client.base_url + "/2/spaces/search" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if query is not None: - params["query"] = query - if state is not None: - params["state"] = state - if max_results is not None: - params["max_results"] = max_results - if space_fields is not None: - params["space.fields"] = ",".join(str(item) for item in space_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if topic_fields is not None: - params["topic.fields"] = ",".join(str(item) for item in topic_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return SearchspacesResponse.model_validate(response_data) - - - def get_spaces_by_creator_ids( - self, - user_ids: List, - space_fields: List = None, - expansions: List = None, - user_fields: List = None, - topic_fields: List = None, - ) -> GetspacesbycreatoridsResponse: - """ - Get Spaces by creator IDs - Retrieves details of Spaces created by specified User IDs. - Args: - user_ids: The IDs of Users to search through. - Args: - space_fields: A comma separated list of Space fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Args: - topic_fields: A comma separated list of Topic fields to display. - Returns: - GetspacesbycreatoridsResponse: Response data - """ - url = self.client.base_url + "/2/spaces/by/creator_ids" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if user_ids is not None: - params["user_ids"] = ",".join(str(item) for item in user_ids) - if space_fields is not None: - params["space.fields"] = ",".join(str(item) for item in space_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if topic_fields is not None: - params["topic.fields"] = ",".join(str(item) for item in topic_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetspacesbycreatoridsResponse.model_validate(response_data) - - - def get_spaces_buyers( - self, - id: str, - pagination_token: str = None, - max_results: int = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetspacesbuyersResponse: - """ - Get Space ticket buyers - Retrieves a list of Users who purchased tickets to a specific Space by its ID. - Args: - id: The ID of the Space to be retrieved. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - max_results: The maximum number of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetspacesbuyersResponse: Response data - """ - url = self.client.base_url + "/2/spaces/{id}/buyers" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if pagination_token is not None: - params["pagination_token"] = pagination_token - if max_results is not None: - params["max_results"] = max_results - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetspacesbuyersResponse.model_validate(response_data) - - - def get_spaces_by_ids( - self, - ids: List, - space_fields: List = None, - expansions: List = None, - user_fields: List = None, - topic_fields: List = None, - ) -> GetspacesbyidsResponse: - """ - Get Spaces by IDs - Retrieves details of multiple Spaces by their IDs. - Args: - ids: The list of Space IDs to return. - Args: - space_fields: A comma separated list of Space fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Args: - topic_fields: A comma separated list of Topic fields to display. - Returns: - GetspacesbyidsResponse: Response data - """ - url = self.client.base_url + "/2/spaces" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if ids is not None: - params["ids"] = ",".join(str(item) for item in ids) - if space_fields is not None: - params["space.fields"] = ",".join(str(item) for item in space_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if topic_fields is not None: - params["topic.fields"] = ",".join(str(item) for item in topic_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetspacesbyidsResponse.model_validate(response_data) - - - def get_spaces_by_id( - self, - id: str, - space_fields: List = None, - expansions: List = None, - user_fields: List = None, - topic_fields: List = None, - ) -> GetspacesbyidResponse: - """ - Get space by ID - Retrieves details of a specific space by its ID. - Args: - id: The ID of the Space to be retrieved. - Args: - space_fields: A comma separated list of Space fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Args: - topic_fields: A comma separated list of Topic fields to display. - Returns: - GetspacesbyidResponse: Response data - """ - url = self.client.base_url + "/2/spaces/{id}" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if space_fields is not None: - params["space.fields"] = ",".join(str(item) for item in space_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if topic_fields is not None: - params["topic.fields"] = ",".join(str(item) for item in topic_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetspacesbyidResponse.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/spaces/models.py b/xdk/python/xdk/python/xdk/spaces/models.py deleted file mode 100644 index c6ae4648..00000000 --- a/xdk/python/xdk/python/xdk/spaces/models.py +++ /dev/null @@ -1,280 +0,0 @@ -""" -Spaces models for the X API. - -This module provides models for the Spaces endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for getSpacesPosts - - -class GetspacespostsResponse(BaseModel): - """Response model for getSpacesPosts""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetspacespostsResponseIncludes"] = None - meta: Optional["GetspacespostsResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetspacespostsResponseIncludes(BaseModel): - """Nested model for GetspacespostsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetspacespostsResponseMeta(BaseModel): - """Nested model for GetspacespostsResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for searchSpaces - - -class SearchspacesResponse(BaseModel): - """Response model for searchSpaces""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["SearchspacesResponseIncludes"] = None - meta: Optional["SearchspacesResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class SearchspacesResponseIncludes(BaseModel): - """Nested model for SearchspacesResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class SearchspacesResponseMeta(BaseModel): - """Nested model for SearchspacesResponseMeta""" - - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getSpacesByCreatorIds - - -class GetspacesbycreatoridsResponse(BaseModel): - """Response model for getSpacesByCreatorIds""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetspacesbycreatoridsResponseIncludes"] = None - meta: Optional["GetspacesbycreatoridsResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetspacesbycreatoridsResponseIncludes(BaseModel): - """Nested model for GetspacesbycreatoridsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetspacesbycreatoridsResponseMeta(BaseModel): - """Nested model for GetspacesbycreatoridsResponseMeta""" - - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getSpacesBuyers - - -class GetspacesbuyersResponse(BaseModel): - """Response model for getSpacesBuyers""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetspacesbuyersResponseIncludes"] = None - meta: Optional["GetspacesbuyersResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetspacesbuyersResponseIncludes(BaseModel): - """Nested model for GetspacesbuyersResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetspacesbuyersResponseMeta(BaseModel): - """Nested model for GetspacesbuyersResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getSpacesByIds - - -class GetspacesbyidsResponse(BaseModel): - """Response model for getSpacesByIds""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetspacesbyidsResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetspacesbyidsResponseIncludes(BaseModel): - """Nested model for GetspacesbyidsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getSpacesById - - -class GetspacesbyidResponse(BaseModel): - """Response model for getSpacesById""" - - data: Optional["GetspacesbyidResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - includes: Optional["GetspacesbyidResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetspacesbyidResponseData(BaseModel): - """Nested model for GetspacesbyidResponseData""" - - created_at: Optional[str] = None - creator_id: Optional[str] = None - ended_at: Optional[str] = None - host_ids: Optional[List] = None - id: Optional[str] = None - invited_user_ids: Optional[List] = None - is_ticketed: Optional[bool] = None - lang: Optional[str] = None - participant_count: Optional[int] = None - scheduled_start: Optional[str] = None - speaker_ids: Optional[List] = None - started_at: Optional[str] = None - state: Optional[str] = None - subscriber_count: Optional[int] = None - title: Optional[str] = None - topics: Optional[List] = None - updated_at: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetspacesbyidResponseIncludes(BaseModel): - """Nested model for GetspacesbyidResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/python/xdk/stream/__init__.py b/xdk/python/xdk/python/xdk/stream/__init__.py deleted file mode 100644 index ef5dca48..00000000 --- a/xdk/python/xdk/python/xdk/stream/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Stream module for the X API. - -This module provides access to the Stream endpoints of the X API. -""" - -from .client import StreamClient - -__all__ = ["StreamClient"] diff --git a/xdk/python/xdk/python/xdk/stream/client.py b/xdk/python/xdk/python/xdk/stream/client.py deleted file mode 100644 index 8d9c50f1..00000000 --- a/xdk/python/xdk/python/xdk/stream/client.py +++ /dev/null @@ -1,1189 +0,0 @@ -""" -Stream client for the X API. - -This module provides a client for interacting with the Stream endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - StreamlikesfirehoseResponse, - Streampostssample10Response, - Streamlikessample10Response, - StreampostsfirehoseResponse, - GetrulecountsResponse, - StreampostsfirehoseenResponse, - StreamlikescomplianceResponse, - StreampostsfirehosekoResponse, - StreamuserscomplianceResponse, - StreampostsResponse, - StreamlabelscomplianceResponse, - StreampostscomplianceResponse, - StreampostssampleResponse, - StreampostsfirehosejaResponse, - StreampostsfirehoseptResponse, - GetrulesResponse, - UpdaterulesRequest, - UpdaterulesResponse, -) - - -class StreamClient: - """Client for Stream operations""" - - - def __init__(self, client: Client): - self.client = client - - - def stream_likes_firehose( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - like_with_tweet_author_fields: List = None, - expansions: List = None, - user_fields: List = None, - tweet_fields: List = None, - ) -> StreamlikesfirehoseResponse: - """ - Stream all Likes - Streams all public Likes in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Likes will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - like_with_tweet_author_fields: A comma separated list of LikeWithTweetAuthor fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - StreamlikesfirehoseResponse: Response data - """ - url = self.client.base_url + "/2/likes/firehose/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if like_with_tweet_author_fields is not None: - params["like_with_tweet_author.fields"] = ",".join( - str(item) for item in like_with_tweet_author_fields - ) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamlikesfirehoseResponse.model_validate(response_data) - - - def stream_posts_sample10( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> Streampostssample10Response: - """ - Stream 10% sampled Posts - Streams a 10% sample of public Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - Streampostssample10Response: Response data - """ - url = self.client.base_url + "/2/tweets/sample10/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return Streampostssample10Response.model_validate(response_data) - - - def stream_likes_sample10( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - like_with_tweet_author_fields: List = None, - expansions: List = None, - user_fields: List = None, - tweet_fields: List = None, - ) -> Streamlikessample10Response: - """ - Stream sampled Likes - Streams a 10% sample of public Likes in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Likes will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - like_with_tweet_author_fields: A comma separated list of LikeWithTweetAuthor fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - Streamlikessample10Response: Response data - """ - url = self.client.base_url + "/2/likes/sample10/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if like_with_tweet_author_fields is not None: - params["like_with_tweet_author.fields"] = ",".join( - str(item) for item in like_with_tweet_author_fields - ) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return Streamlikessample10Response.model_validate(response_data) - - - def stream_posts_firehose( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreampostsfirehoseResponse: - """ - Stream all Posts - Streams all public Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreampostsfirehoseResponse: Response data - """ - url = self.client.base_url + "/2/tweets/firehose/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreampostsfirehoseResponse.model_validate(response_data) - - - def get_rule_counts( - self, - rules_count_fields: List = None, - ) -> GetrulecountsResponse: - """ - Get stream rule counts - Retrieves the count of rules in the active rule set for the filtered stream. - Args: - rules_count_fields: A comma separated list of RulesCount fields to display. - Returns: - GetrulecountsResponse: Response data - """ - url = self.client.base_url + "/2/tweets/search/stream/rules/counts" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if rules_count_fields is not None: - params["rules_count.fields"] = ",".join( - str(item) for item in rules_count_fields - ) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetrulecountsResponse.model_validate(response_data) - - - def stream_posts_firehose_en( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreampostsfirehoseenResponse: - """ - Stream English Posts - Streams all public English-language Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreampostsfirehoseenResponse: Response data - """ - url = self.client.base_url + "/2/tweets/firehose/stream/lang/en" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreampostsfirehoseenResponse.model_validate(response_data) - - - def stream_likes_compliance( - self, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - ) -> StreamlikescomplianceResponse: - """ - Stream Likes compliance data - Streams all compliance data related to Likes for Users. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Likes Compliance events will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp from which the Likes Compliance events will be provided. - Returns: - StreamlikescomplianceResponse: Response data - """ - url = self.client.base_url + "/2/likes/compliance/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamlikescomplianceResponse.model_validate(response_data) - - - def stream_posts_firehose_ko( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreampostsfirehosekoResponse: - """ - Stream Korean Posts - Streams all public Korean-language Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreampostsfirehosekoResponse: Response data - """ - url = self.client.base_url + "/2/tweets/firehose/stream/lang/ko" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreampostsfirehosekoResponse.model_validate(response_data) - - - def stream_users_compliance( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - ) -> StreamuserscomplianceResponse: - """ - Stream Users compliance data - Streams all compliance data related to Users. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the User Compliance events will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp from which the User Compliance events will be provided. - Returns: - StreamuserscomplianceResponse: Response data - """ - url = self.client.base_url + "/2/users/compliance/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamuserscomplianceResponse.model_validate(response_data) - - - def stream_posts( - self, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreampostsResponse: - """ - Stream filtered Posts - Streams Posts in real-time matching the active rule set. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreampostsResponse: Response data - """ - url = self.client.base_url + "/2/tweets/search/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreampostsResponse.model_validate(response_data) - - - def stream_labels_compliance( - self, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - ) -> StreamlabelscomplianceResponse: - """ - Stream Post labels - Streams all labeling events applied to Posts. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Post labels will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp from which the Post labels will be provided. - Returns: - StreamlabelscomplianceResponse: Response data - """ - url = self.client.base_url + "/2/tweets/label/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamlabelscomplianceResponse.model_validate(response_data) - - - def stream_posts_compliance( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - ) -> StreampostscomplianceResponse: - """ - Stream Posts compliance data - Streams all compliance data related to Posts. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Post Compliance events will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Post Compliance events will be provided. - Returns: - StreampostscomplianceResponse: Response data - """ - url = self.client.base_url + "/2/tweets/compliance/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreampostscomplianceResponse.model_validate(response_data) - - - def stream_posts_sample( - self, - backfill_minutes: int = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreampostssampleResponse: - """ - Stream sampled Posts - Streams a 1% sample of public Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreampostssampleResponse: Response data - """ - url = self.client.base_url + "/2/tweets/sample/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreampostssampleResponse.model_validate(response_data) - - - def stream_posts_firehose_ja( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreampostsfirehosejaResponse: - """ - Stream Japanese Posts - Streams all public Japanese-language Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreampostsfirehosejaResponse: Response data - """ - url = self.client.base_url + "/2/tweets/firehose/stream/lang/ja" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreampostsfirehosejaResponse.model_validate(response_data) - - - def stream_posts_firehose_pt( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreampostsfirehoseptResponse: - """ - Stream Portuguese Posts - Streams all public Portuguese-language Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreampostsfirehoseptResponse: Response data - """ - url = self.client.base_url + "/2/tweets/firehose/stream/lang/pt" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreampostsfirehoseptResponse.model_validate(response_data) - - - def get_rules( - self, - ids: List = None, - max_results: int = None, - pagination_token: str = None, - ) -> GetrulesResponse: - """ - Get stream rules - Retrieves the active rule set or a subset of rules for the filtered stream. - Args: - ids: A comma-separated list of Rule IDs. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This value is populated by passing the 'next_token' returned in a request to paginate through results. - Returns: - GetrulesResponse: Response data - """ - url = self.client.base_url + "/2/tweets/search/stream/rules" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if ids is not None: - params["ids"] = ",".join(str(item) for item in ids) - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetrulesResponse.model_validate(response_data) - - - def update_rules( - self, - body: UpdaterulesRequest, - dry_run: bool = None, - delete_all: bool = None, - ) -> UpdaterulesResponse: - """ - Update stream rules - Adds or deletes rules from the active rule set for the filtered stream. - Args: - dry_run: Dry Run can be used with both the add and delete action, with the expected result given, but without actually taking any action in the system (meaning the end state will always be as it was when the request was submitted). This is particularly useful to validate rule changes. - Args: - delete_all: Delete All can be used to delete all of the rules associated this client app, it should be specified with no other parameters. Once deleted, rules cannot be recovered. - body: Request body - Returns: - UpdaterulesResponse: Response data - """ - url = self.client.base_url + "/2/tweets/search/stream/rules" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if dry_run is not None: - params["dry_run"] = dry_run - if delete_all is not None: - params["delete_all"] = delete_all - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return UpdaterulesResponse.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/stream/models.py b/xdk/python/xdk/python/xdk/stream/models.py deleted file mode 100644 index a44ebf1a..00000000 --- a/xdk/python/xdk/python/xdk/stream/models.py +++ /dev/null @@ -1,2214 +0,0 @@ -""" -Stream models for the X API. - -This module provides models for the Stream endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for streamLikesFirehose - - -class StreamlikesfirehoseResponse(BaseModel): - """Response model for streamLikesFirehose""" - - data: Optional["StreamlikesfirehoseResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreamlikesfirehoseResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreamlikesfirehoseResponseData(BaseModel): - """Nested model for StreamlikesfirehoseResponseData""" - - created_at: Optional[str] = None - id: Optional[str] = None - liked_tweet_id: Optional[str] = None - timestamp_ms: Optional[int] = None - tweet_author_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreamlikesfirehoseResponseIncludes(BaseModel): - """Nested model for StreamlikesfirehoseResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamPostsSample10 - - -class Streampostssample10Response(BaseModel): - """Response model for streamPostsSample10""" - - data: Optional["Streampostssample10ResponseData"] = None - errors: Optional[List] = None - includes: Optional["Streampostssample10ResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseData(BaseModel): - """Nested model for Streampostssample10ResponseData""" - - attachments: Optional["Streampostssample10ResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["Streampostssample10ResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["Streampostssample10ResponseDataEntities"] = None - geo: Optional["Streampostssample10ResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional["Streampostssample10ResponseDataNonPublicMetrics"] = ( - None - ) - note_tweet: Optional["Streampostssample10ResponseDataNoteTweet"] = None - organic_metrics: Optional["Streampostssample10ResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["Streampostssample10ResponseDataPromotedMetrics"] = None - public_metrics: Optional["Streampostssample10ResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["Streampostssample10ResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["Streampostssample10ResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataAttachments(BaseModel): - """Nested model for Streampostssample10ResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataEditControls(BaseModel): - """Nested model for Streampostssample10ResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataEntities(BaseModel): - """Nested model for Streampostssample10ResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataGeo(BaseModel): - """Nested model for Streampostssample10ResponseDataGeo""" - - coordinates: Optional["Streampostssample10ResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataGeoCoordinates(BaseModel): - """Nested model for Streampostssample10ResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataNonPublicMetrics(BaseModel): - """Nested model for Streampostssample10ResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataNoteTweet(BaseModel): - """Nested model for Streampostssample10ResponseDataNoteTweet""" - - entities: Optional["Streampostssample10ResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataNoteTweetEntities(BaseModel): - """Nested model for Streampostssample10ResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataOrganicMetrics(BaseModel): - """Nested model for Streampostssample10ResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataPromotedMetrics(BaseModel): - """Nested model for Streampostssample10ResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataPublicMetrics(BaseModel): - """Nested model for Streampostssample10ResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataScopes(BaseModel): - """Nested model for Streampostssample10ResponseDataScopes""" - - followers: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataWithheld(BaseModel): - """Nested model for Streampostssample10ResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseIncludes(BaseModel): - """Nested model for Streampostssample10ResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamLikesSample10 - - -class Streamlikessample10Response(BaseModel): - """Response model for streamLikesSample10""" - - data: Optional["Streamlikessample10ResponseData"] = None - errors: Optional[List] = None - includes: Optional["Streamlikessample10ResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streamlikessample10ResponseData(BaseModel): - """Nested model for Streamlikessample10ResponseData""" - - created_at: Optional[str] = None - id: Optional[str] = None - liked_tweet_id: Optional[str] = None - timestamp_ms: Optional[int] = None - tweet_author_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streamlikessample10ResponseIncludes(BaseModel): - """Nested model for Streamlikessample10ResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamPostsFirehose - - -class StreampostsfirehoseResponse(BaseModel): - """Response model for streamPostsFirehose""" - - data: Optional["StreampostsfirehoseResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreampostsfirehoseResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseData(BaseModel): - """Nested model for StreampostsfirehoseResponseData""" - - attachments: Optional["StreampostsfirehoseResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreampostsfirehoseResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreampostsfirehoseResponseDataEntities"] = None - geo: Optional["StreampostsfirehoseResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional["StreampostsfirehoseResponseDataNonPublicMetrics"] = ( - None - ) - note_tweet: Optional["StreampostsfirehoseResponseDataNoteTweet"] = None - organic_metrics: Optional["StreampostsfirehoseResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreampostsfirehoseResponseDataPromotedMetrics"] = None - public_metrics: Optional["StreampostsfirehoseResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreampostsfirehoseResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreampostsfirehoseResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataAttachments(BaseModel): - """Nested model for StreampostsfirehoseResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataEditControls(BaseModel): - """Nested model for StreampostsfirehoseResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataEntities(BaseModel): - """Nested model for StreampostsfirehoseResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataGeo(BaseModel): - """Nested model for StreampostsfirehoseResponseDataGeo""" - - coordinates: Optional["StreampostsfirehoseResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataGeoCoordinates(BaseModel): - """Nested model for StreampostsfirehoseResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreampostsfirehoseResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataNoteTweet(BaseModel): - """Nested model for StreampostsfirehoseResponseDataNoteTweet""" - - entities: Optional["StreampostsfirehoseResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreampostsfirehoseResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataOrganicMetrics(BaseModel): - """Nested model for StreampostsfirehoseResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataPromotedMetrics(BaseModel): - """Nested model for StreampostsfirehoseResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataPublicMetrics(BaseModel): - """Nested model for StreampostsfirehoseResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataScopes(BaseModel): - """Nested model for StreampostsfirehoseResponseDataScopes""" - - followers: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataWithheld(BaseModel): - """Nested model for StreampostsfirehoseResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseIncludes(BaseModel): - """Nested model for StreampostsfirehoseResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getRuleCounts - - -class GetrulecountsResponse(BaseModel): - """Response model for getRuleCounts""" - - data: Optional["GetrulecountsResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetrulecountsResponseData(BaseModel): - """Nested model for GetrulecountsResponseData""" - - all_project_client_apps: Optional[List] = None - cap_per_client_app: Optional[int] = None - cap_per_project: Optional[int] = None - client_app_rules_count: Optional["GetrulecountsResponseDataClientAppRulesCount"] = ( - None - ) - project_rules_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetrulecountsResponseDataClientAppRulesCount(BaseModel): - """Nested model for GetrulecountsResponseDataClientAppRulesCount""" - - client_app_id: Optional[str] = None - rule_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamPostsFirehoseEn - - -class StreampostsfirehoseenResponse(BaseModel): - """Response model for streamPostsFirehoseEn""" - - data: Optional["StreampostsfirehoseenResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreampostsfirehoseenResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseData(BaseModel): - """Nested model for StreampostsfirehoseenResponseData""" - - attachments: Optional["StreampostsfirehoseenResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreampostsfirehoseenResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreampostsfirehoseenResponseDataEntities"] = None - geo: Optional["StreampostsfirehoseenResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional[ - "StreampostsfirehoseenResponseDataNonPublicMetrics" - ] = None - note_tweet: Optional["StreampostsfirehoseenResponseDataNoteTweet"] = None - organic_metrics: Optional["StreampostsfirehoseenResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreampostsfirehoseenResponseDataPromotedMetrics"] = ( - None - ) - public_metrics: Optional["StreampostsfirehoseenResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreampostsfirehoseenResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreampostsfirehoseenResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataAttachments(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataEditControls(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataEntities(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataGeo(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataGeo""" - - coordinates: Optional["StreampostsfirehoseenResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataGeoCoordinates(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataNoteTweet(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataNoteTweet""" - - entities: Optional["StreampostsfirehoseenResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataOrganicMetrics(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataPromotedMetrics(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataPublicMetrics(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataScopes(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataScopes""" - - followers: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataWithheld(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseIncludes(BaseModel): - """Nested model for StreampostsfirehoseenResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamLikesCompliance - - -class StreamlikescomplianceResponse(BaseModel): - """Response model for streamLikesCompliance""" - - data: Optional[Dict[str, Any]] = Field(default=None) - errors: Optional[List] = Field(default=None) - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamPostsFirehoseKo - - -class StreampostsfirehosekoResponse(BaseModel): - """Response model for streamPostsFirehoseKo""" - - data: Optional["StreampostsfirehosekoResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreampostsfirehosekoResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseData(BaseModel): - """Nested model for StreampostsfirehosekoResponseData""" - - attachments: Optional["StreampostsfirehosekoResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreampostsfirehosekoResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreampostsfirehosekoResponseDataEntities"] = None - geo: Optional["StreampostsfirehosekoResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional[ - "StreampostsfirehosekoResponseDataNonPublicMetrics" - ] = None - note_tweet: Optional["StreampostsfirehosekoResponseDataNoteTweet"] = None - organic_metrics: Optional["StreampostsfirehosekoResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreampostsfirehosekoResponseDataPromotedMetrics"] = ( - None - ) - public_metrics: Optional["StreampostsfirehosekoResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreampostsfirehosekoResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreampostsfirehosekoResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataAttachments(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataEditControls(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataEntities(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataGeo(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataGeo""" - - coordinates: Optional["StreampostsfirehosekoResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataGeoCoordinates(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataNoteTweet(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataNoteTweet""" - - entities: Optional["StreampostsfirehosekoResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataOrganicMetrics(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataPromotedMetrics(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataPublicMetrics(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataScopes(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataScopes""" - - followers: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataWithheld(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseIncludes(BaseModel): - """Nested model for StreampostsfirehosekoResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamUsersCompliance - - -class StreamuserscomplianceResponse(BaseModel): - """Response model for streamUsersCompliance""" - - data: Optional[Any] = Field(default=None, description="User compliance data.") - errors: Optional[List] = Field(default=None) - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamPosts - - -class StreampostsResponse(BaseModel): - """Response model for streamPosts""" - - data: Optional["StreampostsResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreampostsResponseIncludes"] = None - matching_rules: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseData(BaseModel): - """Nested model for StreampostsResponseData""" - - attachments: Optional["StreampostsResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreampostsResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreampostsResponseDataEntities"] = None - geo: Optional["StreampostsResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional["StreampostsResponseDataNonPublicMetrics"] = None - note_tweet: Optional["StreampostsResponseDataNoteTweet"] = None - organic_metrics: Optional["StreampostsResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreampostsResponseDataPromotedMetrics"] = None - public_metrics: Optional["StreampostsResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreampostsResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreampostsResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataAttachments(BaseModel): - """Nested model for StreampostsResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataEditControls(BaseModel): - """Nested model for StreampostsResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataEntities(BaseModel): - """Nested model for StreampostsResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataGeo(BaseModel): - """Nested model for StreampostsResponseDataGeo""" - - coordinates: Optional["StreampostsResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataGeoCoordinates(BaseModel): - """Nested model for StreampostsResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreampostsResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataNoteTweet(BaseModel): - """Nested model for StreampostsResponseDataNoteTweet""" - - entities: Optional["StreampostsResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreampostsResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataOrganicMetrics(BaseModel): - """Nested model for StreampostsResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataPromotedMetrics(BaseModel): - """Nested model for StreampostsResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataPublicMetrics(BaseModel): - """Nested model for StreampostsResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataScopes(BaseModel): - """Nested model for StreampostsResponseDataScopes""" - - followers: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataWithheld(BaseModel): - """Nested model for StreampostsResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseIncludes(BaseModel): - """Nested model for StreampostsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamLabelsCompliance - - -class StreamlabelscomplianceResponse(BaseModel): - """Response model for streamLabelsCompliance""" - - data: Optional[Any] = Field(default=None, description="Tweet label data.") - errors: Optional[List] = Field(default=None) - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamPostsCompliance - - -class StreampostscomplianceResponse(BaseModel): - """Response model for streamPostsCompliance""" - - data: Optional[Any] = Field(default=None, description="Tweet compliance data.") - errors: Optional[List] = Field(default=None) - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamPostsSample - - -class StreampostssampleResponse(BaseModel): - """Response model for streamPostsSample""" - - data: Optional["StreampostssampleResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreampostssampleResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseData(BaseModel): - """Nested model for StreampostssampleResponseData""" - - attachments: Optional["StreampostssampleResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreampostssampleResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreampostssampleResponseDataEntities"] = None - geo: Optional["StreampostssampleResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional["StreampostssampleResponseDataNonPublicMetrics"] = None - note_tweet: Optional["StreampostssampleResponseDataNoteTweet"] = None - organic_metrics: Optional["StreampostssampleResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreampostssampleResponseDataPromotedMetrics"] = None - public_metrics: Optional["StreampostssampleResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreampostssampleResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreampostssampleResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataAttachments(BaseModel): - """Nested model for StreampostssampleResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataEditControls(BaseModel): - """Nested model for StreampostssampleResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataEntities(BaseModel): - """Nested model for StreampostssampleResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataGeo(BaseModel): - """Nested model for StreampostssampleResponseDataGeo""" - - coordinates: Optional["StreampostssampleResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataGeoCoordinates(BaseModel): - """Nested model for StreampostssampleResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreampostssampleResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataNoteTweet(BaseModel): - """Nested model for StreampostssampleResponseDataNoteTweet""" - - entities: Optional["StreampostssampleResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreampostssampleResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataOrganicMetrics(BaseModel): - """Nested model for StreampostssampleResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataPromotedMetrics(BaseModel): - """Nested model for StreampostssampleResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataPublicMetrics(BaseModel): - """Nested model for StreampostssampleResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataScopes(BaseModel): - """Nested model for StreampostssampleResponseDataScopes""" - - followers: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataWithheld(BaseModel): - """Nested model for StreampostssampleResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseIncludes(BaseModel): - """Nested model for StreampostssampleResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamPostsFirehoseJa - - -class StreampostsfirehosejaResponse(BaseModel): - """Response model for streamPostsFirehoseJa""" - - data: Optional["StreampostsfirehosejaResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreampostsfirehosejaResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseData(BaseModel): - """Nested model for StreampostsfirehosejaResponseData""" - - attachments: Optional["StreampostsfirehosejaResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreampostsfirehosejaResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreampostsfirehosejaResponseDataEntities"] = None - geo: Optional["StreampostsfirehosejaResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional[ - "StreampostsfirehosejaResponseDataNonPublicMetrics" - ] = None - note_tweet: Optional["StreampostsfirehosejaResponseDataNoteTweet"] = None - organic_metrics: Optional["StreampostsfirehosejaResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreampostsfirehosejaResponseDataPromotedMetrics"] = ( - None - ) - public_metrics: Optional["StreampostsfirehosejaResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreampostsfirehosejaResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreampostsfirehosejaResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataAttachments(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataEditControls(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataEntities(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataGeo(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataGeo""" - - coordinates: Optional["StreampostsfirehosejaResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataGeoCoordinates(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataNoteTweet(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataNoteTweet""" - - entities: Optional["StreampostsfirehosejaResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataOrganicMetrics(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataPromotedMetrics(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataPublicMetrics(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataScopes(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataScopes""" - - followers: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataWithheld(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseIncludes(BaseModel): - """Nested model for StreampostsfirehosejaResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamPostsFirehosePt - - -class StreampostsfirehoseptResponse(BaseModel): - """Response model for streamPostsFirehosePt""" - - data: Optional["StreampostsfirehoseptResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreampostsfirehoseptResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseData(BaseModel): - """Nested model for StreampostsfirehoseptResponseData""" - - attachments: Optional["StreampostsfirehoseptResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreampostsfirehoseptResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreampostsfirehoseptResponseDataEntities"] = None - geo: Optional["StreampostsfirehoseptResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional[ - "StreampostsfirehoseptResponseDataNonPublicMetrics" - ] = None - note_tweet: Optional["StreampostsfirehoseptResponseDataNoteTweet"] = None - organic_metrics: Optional["StreampostsfirehoseptResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreampostsfirehoseptResponseDataPromotedMetrics"] = ( - None - ) - public_metrics: Optional["StreampostsfirehoseptResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreampostsfirehoseptResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreampostsfirehoseptResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataAttachments(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataEditControls(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataEntities(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataGeo(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataGeo""" - - coordinates: Optional["StreampostsfirehoseptResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataGeoCoordinates(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataNoteTweet(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataNoteTweet""" - - entities: Optional["StreampostsfirehoseptResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataOrganicMetrics(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataPromotedMetrics(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataPublicMetrics(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataScopes(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataScopes""" - - followers: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataWithheld(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseIncludes(BaseModel): - """Nested model for StreampostsfirehoseptResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getRules - - -class GetrulesResponse(BaseModel): - """Response model for getRules""" - - data: Optional[List] = None - meta: Optional["GetrulesResponseMeta"] = Field(default_factory=dict) - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetrulesResponseMeta(BaseModel): - """Nested model for GetrulesResponseMeta""" - - next_token: Optional[str] = None - result_count: Optional[int] = None - sent: Optional[str] = None - summary: Any = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for updateRules - - -class UpdaterulesRequest(BaseModel): - """Request model for updateRules""" - - add: Optional[List] = Field(default=None) - delete: Optional[Dict[str, Any]] = Field( - default=None, - description="IDs and values of all deleted user-specified stream filtering rules.", - ) - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class UpdaterulesResponse(BaseModel): - """Response model for updateRules""" - - data: Optional[List] = None - errors: Optional[List] = None - meta: Optional["UpdaterulesResponseMeta"] = Field(default_factory=dict) - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class UpdaterulesResponseMeta(BaseModel): - """Nested model for UpdaterulesResponseMeta""" - - next_token: Optional[str] = None - result_count: Optional[int] = None - sent: Optional[str] = None - summary: Any = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/python/xdk/trends/__init__.py b/xdk/python/xdk/python/xdk/trends/__init__.py deleted file mode 100644 index 0d15d2c8..00000000 --- a/xdk/python/xdk/python/xdk/trends/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Trends module for the X API. - -This module provides access to the Trends endpoints of the X API. -""" - -from .client import TrendsClient - -__all__ = ["TrendsClient"] diff --git a/xdk/python/xdk/python/xdk/trends/client.py b/xdk/python/xdk/python/xdk/trends/client.py deleted file mode 100644 index f33d9015..00000000 --- a/xdk/python/xdk/python/xdk/trends/client.py +++ /dev/null @@ -1,118 +0,0 @@ -""" -Trends client for the X API. - -This module provides a client for interacting with the Trends endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - GetuserspersonalizedtrendsResponse, - GettrendsbywoeidResponse, -) - - -class TrendsClient: - """Client for Trends operations""" - - - def __init__(self, client: Client): - self.client = client - - - def get_users_personalized_trends( - self, - personalized_trend_fields: List = None, - ) -> GetuserspersonalizedtrendsResponse: - """ - Get personalized Trends - Retrieves personalized trending topics for the authenticated user. - Args: - personalized_trend_fields: A comma separated list of PersonalizedTrend fields to display. - Returns: - GetuserspersonalizedtrendsResponse: Response data - """ - url = self.client.base_url + "/2/users/personalized_trends" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if personalized_trend_fields is not None: - params["personalized_trend.fields"] = ",".join( - str(item) for item in personalized_trend_fields - ) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetuserspersonalizedtrendsResponse.model_validate(response_data) - - - def get_trends_by_woeid( - self, - woeid: int, - max_trends: int = None, - trend_fields: List = None, - ) -> GettrendsbywoeidResponse: - """ - Get Trends by WOEID - Retrieves trending topics for a specific location identified by its WOEID. - Args: - woeid: The WOEID of the place to lookup a trend for. - Args: - max_trends: The maximum number of results. - Args: - trend_fields: A comma separated list of Trend fields to display. - Returns: - GettrendsbywoeidResponse: Response data - """ - url = self.client.base_url + "/2/trends/by/woeid/{woeid}" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if max_trends is not None: - params["max_trends"] = max_trends - if trend_fields is not None: - params["trend.fields"] = ",".join(str(item) for item in trend_fields) - url = url.replace("{woeid}", str(woeid)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GettrendsbywoeidResponse.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/trends/models.py b/xdk/python/xdk/python/xdk/trends/models.py deleted file mode 100644 index c460a9f7..00000000 --- a/xdk/python/xdk/python/xdk/trends/models.py +++ /dev/null @@ -1,39 +0,0 @@ -""" -Trends models for the X API. - -This module provides models for the Trends endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for getUsersPersonalizedTrends - - -class GetuserspersonalizedtrendsResponse(BaseModel): - """Response model for getUsersPersonalizedTrends""" - - data: Optional[List] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getTrendsByWoeid - - -class GettrendsbywoeidResponse(BaseModel): - """Response model for getTrendsByWoeid""" - - data: Optional[List] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/python/xdk/tweets/__init__.py b/xdk/python/xdk/python/xdk/tweets/__init__.py deleted file mode 100644 index d7d8e7c7..00000000 --- a/xdk/python/xdk/python/xdk/tweets/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Tweets module for the X API. - -This module provides access to the Tweets endpoints of the X API. -""" - -from .client import TweetsClient - -__all__ = ["TweetsClient"] diff --git a/xdk/python/xdk/python/xdk/tweets/client.py b/xdk/python/xdk/python/xdk/tweets/client.py deleted file mode 100644 index c122c8d7..00000000 --- a/xdk/python/xdk/python/xdk/tweets/client.py +++ /dev/null @@ -1,2702 +0,0 @@ -""" -Tweets client for the X API. - -This module provides a client for interacting with the Tweets endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - Streampostssample10Response, - GetspacespostsResponse, - GetlistspostsResponse, - GetpostscountsrecentResponse, - SearchpostsrecentResponse, - GetpostscountsallResponse, - StreampostsfirehoseResponse, - GetrulecountsResponse, - StreampostsfirehoseenResponse, - LikepostRequest, - LikepostResponse, - GetpostsanalyticsResponse, - StreampostsfirehosekoResponse, - StreampostsResponse, - GetpostsquotedpostsResponse, - GetusersmentionsResponse, - UnlikepostResponse, - GetpostsbyidResponse, - DeletepostsResponse, - SearchpostsallResponse, - HidepostsreplyRequest, - HidepostsreplyResponse, - StreampostssampleResponse, - GetuserstimelineResponse, - GetuserspostsResponse, - GetspacesbuyersResponse, - RepostpostRequest, - RepostpostResponse, - Getinsights28hrResponse, - GetpostsbyidsResponse, - CreatepostsRequest, - CreatepostsResponse, - GetuserslikedpostsResponse, - GetinsightshistoricalResponse, - StreampostsfirehosejaResponse, - StreampostsfirehoseptResponse, - UnrepostpostResponse, - GetpostsrepostsResponse, - GetrulesResponse, - UpdaterulesRequest, - UpdaterulesResponse, -) - - -class TweetsClient: - """Client for Tweets operations""" - - - def __init__(self, client: Client): - self.client = client - - - def stream_posts_sample10( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> Streampostssample10Response: - """ - Stream 10% sampled Posts - Streams a 10% sample of public Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - Streampostssample10Response: Response data - """ - url = self.client.base_url + "/2/tweets/sample10/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return Streampostssample10Response.model_validate(response_data) - - - def get_spaces_posts( - self, - id: str, - max_results: int = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetspacespostsResponse: - """ - Get Space Posts - Retrieves a list of Posts shared in a specific Space by its ID. - Args: - id: The ID of the Space to be retrieved. - Args: - max_results: The number of Posts to fetch from the provided space. If not provided, the value will default to the maximum of 100. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetspacespostsResponse: Response data - """ - url = self.client.base_url + "/2/spaces/{id}/tweets" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetspacespostsResponse.model_validate(response_data) - - - def get_lists_posts( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetlistspostsResponse: - """ - Get List Posts - Retrieves a list of Posts associated with a specific List by its ID. - Args: - id: The ID of the List. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetlistspostsResponse: Response data - """ - url = self.client.base_url + "/2/lists/{id}/tweets" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetlistspostsResponse.model_validate(response_data) - - - def get_posts_counts_recent( - self, - query: str, - start_time: str = None, - end_time: str = None, - since_id: str = None, - until_id: str = None, - next_token: str = None, - pagination_token: str = None, - granularity: str = None, - search_count_fields: List = None, - ) -> GetpostscountsrecentResponse: - """ - Get count of recent Posts - Retrieves the count of Posts from the last 7 days matching a search query. - Args: - query: One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The oldest UTC timestamp (from most recent 7 days) from which the Posts will be provided. Timestamp is in second granularity and is inclusive (i.e. 12:00:01 includes the first second of the minute). - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The newest, most recent UTC timestamp to which the Posts will be provided. Timestamp is in second granularity and is exclusive (i.e. 12:00:01 excludes the first second of the minute). - Args: - since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID. - Args: - until_id: Returns results with a Post ID less than (that is, older than) the specified ID. - Args: - next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - pagination_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - granularity: The granularity for the search counts results. - Args: - search_count_fields: A comma separated list of SearchCount fields to display. - Returns: - GetpostscountsrecentResponse: Response data - """ - url = self.client.base_url + "/2/tweets/counts/recent" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if query is not None: - params["query"] = query - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if since_id is not None: - params["since_id"] = since_id - if until_id is not None: - params["until_id"] = until_id - if next_token is not None: - params["next_token"] = next_token - if pagination_token is not None: - params["pagination_token"] = pagination_token - if granularity is not None: - params["granularity"] = granularity - if search_count_fields is not None: - params["search_count.fields"] = ",".join( - str(item) for item in search_count_fields - ) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetpostscountsrecentResponse.model_validate(response_data) - - - def search_posts_recent( - self, - query: str, - start_time: str = None, - end_time: str = None, - since_id: str = None, - until_id: str = None, - max_results: int = None, - next_token: str = None, - pagination_token: str = None, - sort_order: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> SearchpostsrecentResponse: - """ - Search recent Posts - Retrieves Posts from the last 7 days matching a search query. - Args: - query: One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The oldest UTC timestamp from which the Posts will be provided. Timestamp is in second granularity and is inclusive (i.e. 12:00:01 includes the first second of the minute). - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The newest, most recent UTC timestamp to which the Posts will be provided. Timestamp is in second granularity and is exclusive (i.e. 12:00:01 excludes the first second of the minute). - Args: - since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID. - Args: - until_id: Returns results with a Post ID less than (that is, older than) the specified ID. - Args: - max_results: The maximum number of search results to be returned by a request. - Args: - next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - pagination_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - sort_order: This order in which to return results. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - SearchpostsrecentResponse: Response data - """ - url = self.client.base_url + "/2/tweets/search/recent" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if query is not None: - params["query"] = query - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if since_id is not None: - params["since_id"] = since_id - if until_id is not None: - params["until_id"] = until_id - if max_results is not None: - params["max_results"] = max_results - if next_token is not None: - params["next_token"] = next_token - if pagination_token is not None: - params["pagination_token"] = pagination_token - if sort_order is not None: - params["sort_order"] = sort_order - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return SearchpostsrecentResponse.model_validate(response_data) - - - def get_posts_counts_all( - self, - query: str, - start_time: str = None, - end_time: str = None, - since_id: str = None, - until_id: str = None, - next_token: str = None, - pagination_token: str = None, - granularity: str = None, - search_count_fields: List = None, - ) -> GetpostscountsallResponse: - """ - Get count of all Posts - Retrieves the count of Posts matching a search query from the full archive. - Args: - query: One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The oldest UTC timestamp (from most recent 7 days) from which the Posts will be provided. Timestamp is in second granularity and is inclusive (i.e. 12:00:01 includes the first second of the minute). - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The newest, most recent UTC timestamp to which the Posts will be provided. Timestamp is in second granularity and is exclusive (i.e. 12:00:01 excludes the first second of the minute). - Args: - since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID. - Args: - until_id: Returns results with a Post ID less than (that is, older than) the specified ID. - Args: - next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - pagination_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - granularity: The granularity for the search counts results. - Args: - search_count_fields: A comma separated list of SearchCount fields to display. - Returns: - GetpostscountsallResponse: Response data - """ - url = self.client.base_url + "/2/tweets/counts/all" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if query is not None: - params["query"] = query - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if since_id is not None: - params["since_id"] = since_id - if until_id is not None: - params["until_id"] = until_id - if next_token is not None: - params["next_token"] = next_token - if pagination_token is not None: - params["pagination_token"] = pagination_token - if granularity is not None: - params["granularity"] = granularity - if search_count_fields is not None: - params["search_count.fields"] = ",".join( - str(item) for item in search_count_fields - ) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetpostscountsallResponse.model_validate(response_data) - - - def stream_posts_firehose( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreampostsfirehoseResponse: - """ - Stream all Posts - Streams all public Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreampostsfirehoseResponse: Response data - """ - url = self.client.base_url + "/2/tweets/firehose/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreampostsfirehoseResponse.model_validate(response_data) - - - def get_rule_counts( - self, - rules_count_fields: List = None, - ) -> GetrulecountsResponse: - """ - Get stream rule counts - Retrieves the count of rules in the active rule set for the filtered stream. - Args: - rules_count_fields: A comma separated list of RulesCount fields to display. - Returns: - GetrulecountsResponse: Response data - """ - url = self.client.base_url + "/2/tweets/search/stream/rules/counts" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if rules_count_fields is not None: - params["rules_count.fields"] = ",".join( - str(item) for item in rules_count_fields - ) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetrulecountsResponse.model_validate(response_data) - - - def stream_posts_firehose_en( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreampostsfirehoseenResponse: - """ - Stream English Posts - Streams all public English-language Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreampostsfirehoseenResponse: Response data - """ - url = self.client.base_url + "/2/tweets/firehose/stream/lang/en" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreampostsfirehoseenResponse.model_validate(response_data) - - - def like_post( - self, - id: str, - body: Optional[LikepostRequest] = None, - ) -> LikepostResponse: - """ - Like Post - Causes the authenticated user to Like a specific Post by its ID. - Args: - id: The ID of the authenticated source User that is requesting to like the Post. - body: Request body - Returns: - LikepostResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/likes" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return LikepostResponse.model_validate(response_data) - - - def get_posts_analytics( - self, - ids: List, - end_time: str, - start_time: str, - granularity: str, - analytics_fields: List = None, - ) -> GetpostsanalyticsResponse: - """ - Get Post analytics - Retrieves analytics data for specified Posts within a defined time range. - Args: - ids: A comma separated list of Post IDs. Up to 100 are allowed in a single request. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range. - Args: - granularity: The granularity for the search counts results. - Args: - analytics_fields: A comma separated list of Analytics fields to display. - Returns: - GetpostsanalyticsResponse: Response data - """ - url = self.client.base_url + "/2/tweets/analytics" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if ids is not None: - params["ids"] = ",".join(str(item) for item in ids) - if end_time is not None: - params["end_time"] = end_time - if start_time is not None: - params["start_time"] = start_time - if granularity is not None: - params["granularity"] = granularity - if analytics_fields is not None: - params["analytics.fields"] = ",".join( - str(item) for item in analytics_fields - ) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetpostsanalyticsResponse.model_validate(response_data) - - - def stream_posts_firehose_ko( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreampostsfirehosekoResponse: - """ - Stream Korean Posts - Streams all public Korean-language Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreampostsfirehosekoResponse: Response data - """ - url = self.client.base_url + "/2/tweets/firehose/stream/lang/ko" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreampostsfirehosekoResponse.model_validate(response_data) - - - def stream_posts( - self, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreampostsResponse: - """ - Stream filtered Posts - Streams Posts in real-time matching the active rule set. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreampostsResponse: Response data - """ - url = self.client.base_url + "/2/tweets/search/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreampostsResponse.model_validate(response_data) - - - def get_posts_quoted_posts( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - exclude: List = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetpostsquotedpostsResponse: - """ - Get Quoted Posts - Retrieves a list of Posts that quote a specific Post by its ID. - Args: - id: A single Post ID. - Args: - max_results: The maximum number of results to be returned. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - exclude: The set of entities to exclude (e.g. 'replies' or 'retweets'). - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetpostsquotedpostsResponse: Response data - """ - url = self.client.base_url + "/2/tweets/{id}/quote_tweets" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if exclude is not None: - params["exclude"] = ",".join(str(item) for item in exclude) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetpostsquotedpostsResponse.model_validate(response_data) - - - def get_users_mentions( - self, - id: str, - since_id: str = None, - until_id: str = None, - max_results: int = None, - pagination_token: str = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetusersmentionsResponse: - """ - Get mentions - Retrieves a list of Posts that mention a specific User by their ID. - Args: - id: The ID of the User to lookup. - Args: - since_id: The minimum Post ID to be included in the result set. This parameter takes precedence over start_time if both are specified. - Args: - until_id: The maximum Post ID to be included in the result set. This parameter takes precedence over end_time if both are specified. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Posts will be provided. The since_id parameter takes precedence if it is also specified. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. The until_id parameter takes precedence if it is also specified. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetusersmentionsResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/mentions" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if since_id is not None: - params["since_id"] = since_id - if until_id is not None: - params["until_id"] = until_id - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetusersmentionsResponse.model_validate(response_data) - - - def unlike_post( - self, - id: str, - tweet_id: str, - ) -> UnlikepostResponse: - """ - Unlike Post - Causes the authenticated user to Unlike a specific Post by its ID. - Args: - id: The ID of the authenticated source User that is requesting to unlike the Post. - Args: - tweet_id: The ID of the Post that the User is requesting to unlike. - Returns: - UnlikepostResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/likes/{tweet_id}" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - url = url.replace("{tweet_id}", str(tweet_id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.delete( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.delete( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return UnlikepostResponse.model_validate(response_data) - - - def get_posts_by_id( - self, - id: str, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetpostsbyidResponse: - """ - Get Post by ID - Retrieves details of a specific Post by its ID. - Args: - id: A single Post ID. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetpostsbyidResponse: Response data - """ - url = self.client.base_url + "/2/tweets/{id}" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetpostsbyidResponse.model_validate(response_data) - - - def delete_posts( - self, - id: str, - ) -> DeletepostsResponse: - """ - Delete Post - Deletes a specific Post by its ID, if owned by the authenticated user. - Args: - id: The ID of the Post to be deleted. - Returns: - DeletepostsResponse: Response data - """ - url = self.client.base_url + "/2/tweets/{id}" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.delete( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.delete( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return DeletepostsResponse.model_validate(response_data) - - - def search_posts_all( - self, - query: str, - start_time: str = None, - end_time: str = None, - since_id: str = None, - until_id: str = None, - max_results: int = None, - next_token: str = None, - pagination_token: str = None, - sort_order: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> SearchpostsallResponse: - """ - Search all Posts - Retrieves Posts from the full archive matching a search query. - Args: - query: One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The oldest UTC timestamp from which the Posts will be provided. Timestamp is in second granularity and is inclusive (i.e. 12:00:01 includes the first second of the minute). - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The newest, most recent UTC timestamp to which the Posts will be provided. Timestamp is in second granularity and is exclusive (i.e. 12:00:01 excludes the first second of the minute). - Args: - since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID. - Args: - until_id: Returns results with a Post ID less than (that is, older than) the specified ID. - Args: - max_results: The maximum number of search results to be returned by a request. - Args: - next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - pagination_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - sort_order: This order in which to return results. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - SearchpostsallResponse: Response data - """ - url = self.client.base_url + "/2/tweets/search/all" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if query is not None: - params["query"] = query - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if since_id is not None: - params["since_id"] = since_id - if until_id is not None: - params["until_id"] = until_id - if max_results is not None: - params["max_results"] = max_results - if next_token is not None: - params["next_token"] = next_token - if pagination_token is not None: - params["pagination_token"] = pagination_token - if sort_order is not None: - params["sort_order"] = sort_order - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return SearchpostsallResponse.model_validate(response_data) - - - def hide_posts_reply( - self, - tweet_id: str, - body: Optional[HidepostsreplyRequest] = None, - ) -> HidepostsreplyResponse: - """ - Hide reply - Hides or unhides a reply to a conversation owned by the authenticated user. - Args: - tweet_id: The ID of the reply that you want to hide or unhide. - body: Request body - Returns: - HidepostsreplyResponse: Response data - """ - url = self.client.base_url + "/2/tweets/{tweet_id}/hidden" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{tweet_id}", str(tweet_id)) - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.put( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.put( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return HidepostsreplyResponse.model_validate(response_data) - - - def stream_posts_sample( - self, - backfill_minutes: int = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreampostssampleResponse: - """ - Stream sampled Posts - Streams a 1% sample of public Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreampostssampleResponse: Response data - """ - url = self.client.base_url + "/2/tweets/sample/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreampostssampleResponse.model_validate(response_data) - - - def get_users_timeline( - self, - id: str, - since_id: str = None, - until_id: str = None, - max_results: int = None, - pagination_token: str = None, - exclude: List = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetuserstimelineResponse: - """ - Get Timeline - Retrieves a reverse chronological list of Posts in the authenticated User’s Timeline. - Args: - id: The ID of the authenticated source User to list Reverse Chronological Timeline Posts of. - Args: - since_id: The minimum Post ID to be included in the result set. This parameter takes precedence over start_time if both are specified. - Args: - until_id: The maximum Post ID to be included in the result set. This parameter takes precedence over end_time if both are specified. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - exclude: The set of entities to exclude (e.g. 'replies' or 'retweets'). - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Posts will be provided. The since_id parameter takes precedence if it is also specified. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. The until_id parameter takes precedence if it is also specified. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetuserstimelineResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/timelines/reverse_chronological" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if since_id is not None: - params["since_id"] = since_id - if until_id is not None: - params["until_id"] = until_id - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if exclude is not None: - params["exclude"] = ",".join(str(item) for item in exclude) - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetuserstimelineResponse.model_validate(response_data) - - - def get_users_posts( - self, - id: str, - since_id: str = None, - until_id: str = None, - max_results: int = None, - pagination_token: str = None, - exclude: List = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetuserspostsResponse: - """ - Get Posts - Retrieves a list of posts authored by a specific User by their ID. - Args: - id: The ID of the User to lookup. - Args: - since_id: The minimum Post ID to be included in the result set. This parameter takes precedence over start_time if both are specified. - Args: - until_id: The maximum Post ID to be included in the result set. This parameter takes precedence over end_time if both are specified. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - exclude: The set of entities to exclude (e.g. 'replies' or 'retweets'). - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Posts will be provided. The since_id parameter takes precedence if it is also specified. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. The until_id parameter takes precedence if it is also specified. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetuserspostsResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/tweets" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if since_id is not None: - params["since_id"] = since_id - if until_id is not None: - params["until_id"] = until_id - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if exclude is not None: - params["exclude"] = ",".join(str(item) for item in exclude) - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetuserspostsResponse.model_validate(response_data) - - - def get_spaces_buyers( - self, - id: str, - pagination_token: str = None, - max_results: int = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetspacesbuyersResponse: - """ - Get Space ticket buyers - Retrieves a list of Users who purchased tickets to a specific Space by its ID. - Args: - id: The ID of the Space to be retrieved. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - max_results: The maximum number of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetspacesbuyersResponse: Response data - """ - url = self.client.base_url + "/2/spaces/{id}/buyers" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if pagination_token is not None: - params["pagination_token"] = pagination_token - if max_results is not None: - params["max_results"] = max_results - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetspacesbuyersResponse.model_validate(response_data) - - - def repost_post( - self, - id: str, - body: Optional[RepostpostRequest] = None, - ) -> RepostpostResponse: - """ - Repost Post - Causes the authenticated user to repost a specific Post by its ID. - Args: - id: The ID of the authenticated source User that is requesting to repost the Post. - body: Request body - Returns: - RepostpostResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/retweets" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return RepostpostResponse.model_validate(response_data) - - - def get_insights28_hr( - self, - tweet_ids: List, - granularity: str, - requested_metrics: List, - engagement_fields: List = None, - ) -> Getinsights28hrResponse: - """ - Get 28-hour Post insights - Retrieves engagement metrics for specified Posts over the last 28 hours. - Args: - tweet_ids: List of PostIds for 28hr metrics. - Args: - granularity: granularity of metrics response. - Args: - requested_metrics: request metrics for historical request. - Args: - engagement_fields: A comma separated list of Engagement fields to display. - Returns: - Getinsights28hrResponse: Response data - """ - url = self.client.base_url + "/2/insights/28hr" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if tweet_ids is not None: - params["tweet_ids"] = ",".join(str(item) for item in tweet_ids) - if granularity is not None: - params["granularity"] = granularity - if requested_metrics is not None: - params["requested_metrics"] = ",".join( - str(item) for item in requested_metrics - ) - if engagement_fields is not None: - params["engagement.fields"] = ",".join( - str(item) for item in engagement_fields - ) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return Getinsights28hrResponse.model_validate(response_data) - - - def get_posts_by_ids( - self, - ids: List, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetpostsbyidsResponse: - """ - Get Posts by IDs - Retrieves details of multiple Posts by their IDs. - Args: - ids: A comma separated list of Post IDs. Up to 100 are allowed in a single request. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetpostsbyidsResponse: Response data - """ - url = self.client.base_url + "/2/tweets" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if ids is not None: - params["ids"] = ",".join(str(item) for item in ids) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetpostsbyidsResponse.model_validate(response_data) - - - def create_posts( - self, - body: CreatepostsRequest, - ) -> Dict[str, Any]: - """ - Create Post - Creates a new Post for the authenticated user. - body: Request body - Returns: - CreatepostsResponse: Response data - """ - url = self.client.base_url + "/2/tweets" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return CreatepostsResponse.model_validate(response_data) - - - def get_users_liked_posts( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetuserslikedpostsResponse: - """ - Get liked Posts - Retrieves a list of Posts liked by a specific User by their ID. - Args: - id: The ID of the User to lookup. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetuserslikedpostsResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/liked_tweets" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetuserslikedpostsResponse.model_validate(response_data) - - - def get_insights_historical( - self, - tweet_ids: List, - end_time: str, - start_time: str, - granularity: str, - requested_metrics: List, - engagement_fields: List = None, - ) -> GetinsightshistoricalResponse: - """ - Get historical Post insights - Retrieves historical engagement metrics for specified Posts within a defined time range. - Args: - tweet_ids: List of PostIds for historical metrics. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range. - Args: - granularity: granularity of metrics response. - Args: - requested_metrics: request metrics for historical request. - Args: - engagement_fields: A comma separated list of Engagement fields to display. - Returns: - GetinsightshistoricalResponse: Response data - """ - url = self.client.base_url + "/2/insights/historical" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if tweet_ids is not None: - params["tweet_ids"] = ",".join(str(item) for item in tweet_ids) - if end_time is not None: - params["end_time"] = end_time - if start_time is not None: - params["start_time"] = start_time - if granularity is not None: - params["granularity"] = granularity - if requested_metrics is not None: - params["requested_metrics"] = ",".join( - str(item) for item in requested_metrics - ) - if engagement_fields is not None: - params["engagement.fields"] = ",".join( - str(item) for item in engagement_fields - ) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetinsightshistoricalResponse.model_validate(response_data) - - - def stream_posts_firehose_ja( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreampostsfirehosejaResponse: - """ - Stream Japanese Posts - Streams all public Japanese-language Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreampostsfirehosejaResponse: Response data - """ - url = self.client.base_url + "/2/tweets/firehose/stream/lang/ja" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreampostsfirehosejaResponse.model_validate(response_data) - - - def stream_posts_firehose_pt( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreampostsfirehoseptResponse: - """ - Stream Portuguese Posts - Streams all public Portuguese-language Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreampostsfirehoseptResponse: Response data - """ - url = self.client.base_url + "/2/tweets/firehose/stream/lang/pt" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreampostsfirehoseptResponse.model_validate(response_data) - - - def unrepost_post( - self, - id: str, - source_tweet_id: str, - ) -> UnrepostpostResponse: - """ - Unrepost Post - Causes the authenticated user to unrepost a specific Post by its ID. - Args: - id: The ID of the authenticated source User that is requesting to repost the Post. - Args: - source_tweet_id: The ID of the Post that the User is requesting to unretweet. - Returns: - UnrepostpostResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/retweets/{source_tweet_id}" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - url = url.replace("{source_tweet_id}", str(source_tweet_id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.delete( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.delete( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return UnrepostpostResponse.model_validate(response_data) - - - def get_posts_reposts( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetpostsrepostsResponse: - """ - Get Reposts - Retrieves a list of Posts that repost a specific Post by its ID. - Args: - id: A single Post ID. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetpostsrepostsResponse: Response data - """ - url = self.client.base_url + "/2/tweets/{id}/retweets" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetpostsrepostsResponse.model_validate(response_data) - - - def get_rules( - self, - ids: List = None, - max_results: int = None, - pagination_token: str = None, - ) -> GetrulesResponse: - """ - Get stream rules - Retrieves the active rule set or a subset of rules for the filtered stream. - Args: - ids: A comma-separated list of Rule IDs. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This value is populated by passing the 'next_token' returned in a request to paginate through results. - Returns: - GetrulesResponse: Response data - """ - url = self.client.base_url + "/2/tweets/search/stream/rules" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if ids is not None: - params["ids"] = ",".join(str(item) for item in ids) - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetrulesResponse.model_validate(response_data) - - - def update_rules( - self, - body: UpdaterulesRequest, - dry_run: bool = None, - delete_all: bool = None, - ) -> UpdaterulesResponse: - """ - Update stream rules - Adds or deletes rules from the active rule set for the filtered stream. - Args: - dry_run: Dry Run can be used with both the add and delete action, with the expected result given, but without actually taking any action in the system (meaning the end state will always be as it was when the request was submitted). This is particularly useful to validate rule changes. - Args: - delete_all: Delete All can be used to delete all of the rules associated this client app, it should be specified with no other parameters. Once deleted, rules cannot be recovered. - body: Request body - Returns: - UpdaterulesResponse: Response data - """ - url = self.client.base_url + "/2/tweets/search/stream/rules" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if dry_run is not None: - params["dry_run"] = dry_run - if delete_all is not None: - params["delete_all"] = delete_all - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return UpdaterulesResponse.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/tweets/models.py b/xdk/python/xdk/python/xdk/tweets/models.py deleted file mode 100644 index 72a5488f..00000000 --- a/xdk/python/xdk/python/xdk/tweets/models.py +++ /dev/null @@ -1,3245 +0,0 @@ -""" -Tweets models for the X API. - -This module provides models for the Tweets endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for streamPostsSample10 - - -class Streampostssample10Response(BaseModel): - """Response model for streamPostsSample10""" - - data: Optional["Streampostssample10ResponseData"] = None - errors: Optional[List] = None - includes: Optional["Streampostssample10ResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseData(BaseModel): - """Nested model for Streampostssample10ResponseData""" - - attachments: Optional["Streampostssample10ResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["Streampostssample10ResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["Streampostssample10ResponseDataEntities"] = None - geo: Optional["Streampostssample10ResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional["Streampostssample10ResponseDataNonPublicMetrics"] = ( - None - ) - note_tweet: Optional["Streampostssample10ResponseDataNoteTweet"] = None - organic_metrics: Optional["Streampostssample10ResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["Streampostssample10ResponseDataPromotedMetrics"] = None - public_metrics: Optional["Streampostssample10ResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["Streampostssample10ResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["Streampostssample10ResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataAttachments(BaseModel): - """Nested model for Streampostssample10ResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataEditControls(BaseModel): - """Nested model for Streampostssample10ResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataEntities(BaseModel): - """Nested model for Streampostssample10ResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataGeo(BaseModel): - """Nested model for Streampostssample10ResponseDataGeo""" - - coordinates: Optional["Streampostssample10ResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataGeoCoordinates(BaseModel): - """Nested model for Streampostssample10ResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataNonPublicMetrics(BaseModel): - """Nested model for Streampostssample10ResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataNoteTweet(BaseModel): - """Nested model for Streampostssample10ResponseDataNoteTweet""" - - entities: Optional["Streampostssample10ResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataNoteTweetEntities(BaseModel): - """Nested model for Streampostssample10ResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataOrganicMetrics(BaseModel): - """Nested model for Streampostssample10ResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataPromotedMetrics(BaseModel): - """Nested model for Streampostssample10ResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataPublicMetrics(BaseModel): - """Nested model for Streampostssample10ResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataScopes(BaseModel): - """Nested model for Streampostssample10ResponseDataScopes""" - - followers: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseDataWithheld(BaseModel): - """Nested model for Streampostssample10ResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class Streampostssample10ResponseIncludes(BaseModel): - """Nested model for Streampostssample10ResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getSpacesPosts - - -class GetspacespostsResponse(BaseModel): - """Response model for getSpacesPosts""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetspacespostsResponseIncludes"] = None - meta: Optional["GetspacespostsResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetspacespostsResponseIncludes(BaseModel): - """Nested model for GetspacespostsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetspacespostsResponseMeta(BaseModel): - """Nested model for GetspacespostsResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getListsPosts - - -class GetlistspostsResponse(BaseModel): - """Response model for getListsPosts""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetlistspostsResponseIncludes"] = None - meta: Optional["GetlistspostsResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetlistspostsResponseIncludes(BaseModel): - """Nested model for GetlistspostsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetlistspostsResponseMeta(BaseModel): - """Nested model for GetlistspostsResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getPostsCountsRecent - - -class GetpostscountsrecentResponse(BaseModel): - """Response model for getPostsCountsRecent""" - - data: Optional[List] = None - errors: Optional[List] = None - meta: Optional["GetpostscountsrecentResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostscountsrecentResponseMeta(BaseModel): - """Nested model for GetpostscountsrecentResponseMeta""" - - newest_id: Optional[str] = None - next_token: Optional[str] = None - oldest_id: Optional[str] = None - total_tweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for searchPostsRecent - - -class SearchpostsrecentResponse(BaseModel): - """Response model for searchPostsRecent""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["SearchpostsrecentResponseIncludes"] = None - meta: Optional["SearchpostsrecentResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class SearchpostsrecentResponseIncludes(BaseModel): - """Nested model for SearchpostsrecentResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class SearchpostsrecentResponseMeta(BaseModel): - """Nested model for SearchpostsrecentResponseMeta""" - - newest_id: Optional[str] = None - next_token: Optional[str] = None - oldest_id: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getPostsCountsAll - - -class GetpostscountsallResponse(BaseModel): - """Response model for getPostsCountsAll""" - - data: Optional[List] = None - errors: Optional[List] = None - meta: Optional["GetpostscountsallResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostscountsallResponseMeta(BaseModel): - """Nested model for GetpostscountsallResponseMeta""" - - newest_id: Optional[str] = None - next_token: Optional[str] = None - oldest_id: Optional[str] = None - total_tweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamPostsFirehose - - -class StreampostsfirehoseResponse(BaseModel): - """Response model for streamPostsFirehose""" - - data: Optional["StreampostsfirehoseResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreampostsfirehoseResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseData(BaseModel): - """Nested model for StreampostsfirehoseResponseData""" - - attachments: Optional["StreampostsfirehoseResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreampostsfirehoseResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreampostsfirehoseResponseDataEntities"] = None - geo: Optional["StreampostsfirehoseResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional["StreampostsfirehoseResponseDataNonPublicMetrics"] = ( - None - ) - note_tweet: Optional["StreampostsfirehoseResponseDataNoteTweet"] = None - organic_metrics: Optional["StreampostsfirehoseResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreampostsfirehoseResponseDataPromotedMetrics"] = None - public_metrics: Optional["StreampostsfirehoseResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreampostsfirehoseResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreampostsfirehoseResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataAttachments(BaseModel): - """Nested model for StreampostsfirehoseResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataEditControls(BaseModel): - """Nested model for StreampostsfirehoseResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataEntities(BaseModel): - """Nested model for StreampostsfirehoseResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataGeo(BaseModel): - """Nested model for StreampostsfirehoseResponseDataGeo""" - - coordinates: Optional["StreampostsfirehoseResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataGeoCoordinates(BaseModel): - """Nested model for StreampostsfirehoseResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreampostsfirehoseResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataNoteTweet(BaseModel): - """Nested model for StreampostsfirehoseResponseDataNoteTweet""" - - entities: Optional["StreampostsfirehoseResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreampostsfirehoseResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataOrganicMetrics(BaseModel): - """Nested model for StreampostsfirehoseResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataPromotedMetrics(BaseModel): - """Nested model for StreampostsfirehoseResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataPublicMetrics(BaseModel): - """Nested model for StreampostsfirehoseResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataScopes(BaseModel): - """Nested model for StreampostsfirehoseResponseDataScopes""" - - followers: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseDataWithheld(BaseModel): - """Nested model for StreampostsfirehoseResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseResponseIncludes(BaseModel): - """Nested model for StreampostsfirehoseResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getRuleCounts - - -class GetrulecountsResponse(BaseModel): - """Response model for getRuleCounts""" - - data: Optional["GetrulecountsResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetrulecountsResponseData(BaseModel): - """Nested model for GetrulecountsResponseData""" - - all_project_client_apps: Optional[List] = None - cap_per_client_app: Optional[int] = None - cap_per_project: Optional[int] = None - client_app_rules_count: Optional["GetrulecountsResponseDataClientAppRulesCount"] = ( - None - ) - project_rules_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetrulecountsResponseDataClientAppRulesCount(BaseModel): - """Nested model for GetrulecountsResponseDataClientAppRulesCount""" - - client_app_id: Optional[str] = None - rule_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamPostsFirehoseEn - - -class StreampostsfirehoseenResponse(BaseModel): - """Response model for streamPostsFirehoseEn""" - - data: Optional["StreampostsfirehoseenResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreampostsfirehoseenResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseData(BaseModel): - """Nested model for StreampostsfirehoseenResponseData""" - - attachments: Optional["StreampostsfirehoseenResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreampostsfirehoseenResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreampostsfirehoseenResponseDataEntities"] = None - geo: Optional["StreampostsfirehoseenResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional[ - "StreampostsfirehoseenResponseDataNonPublicMetrics" - ] = None - note_tweet: Optional["StreampostsfirehoseenResponseDataNoteTweet"] = None - organic_metrics: Optional["StreampostsfirehoseenResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreampostsfirehoseenResponseDataPromotedMetrics"] = ( - None - ) - public_metrics: Optional["StreampostsfirehoseenResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreampostsfirehoseenResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreampostsfirehoseenResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataAttachments(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataEditControls(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataEntities(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataGeo(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataGeo""" - - coordinates: Optional["StreampostsfirehoseenResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataGeoCoordinates(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataNoteTweet(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataNoteTweet""" - - entities: Optional["StreampostsfirehoseenResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataOrganicMetrics(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataPromotedMetrics(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataPublicMetrics(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataScopes(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataScopes""" - - followers: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseDataWithheld(BaseModel): - """Nested model for StreampostsfirehoseenResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseenResponseIncludes(BaseModel): - """Nested model for StreampostsfirehoseenResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for likePost - - -class LikepostRequest(BaseModel): - """Request model for likePost""" - - tweet_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class LikepostResponse(BaseModel): - """Response model for likePost""" - - data: Optional["LikepostResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class LikepostResponseData(BaseModel): - """Nested model for LikepostResponseData""" - - liked: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getPostsAnalytics - - -class GetpostsanalyticsResponse(BaseModel): - """Response model for getPostsAnalytics""" - - data: Optional[List] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamPostsFirehoseKo - - -class StreampostsfirehosekoResponse(BaseModel): - """Response model for streamPostsFirehoseKo""" - - data: Optional["StreampostsfirehosekoResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreampostsfirehosekoResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseData(BaseModel): - """Nested model for StreampostsfirehosekoResponseData""" - - attachments: Optional["StreampostsfirehosekoResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreampostsfirehosekoResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreampostsfirehosekoResponseDataEntities"] = None - geo: Optional["StreampostsfirehosekoResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional[ - "StreampostsfirehosekoResponseDataNonPublicMetrics" - ] = None - note_tweet: Optional["StreampostsfirehosekoResponseDataNoteTweet"] = None - organic_metrics: Optional["StreampostsfirehosekoResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreampostsfirehosekoResponseDataPromotedMetrics"] = ( - None - ) - public_metrics: Optional["StreampostsfirehosekoResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreampostsfirehosekoResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreampostsfirehosekoResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataAttachments(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataEditControls(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataEntities(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataGeo(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataGeo""" - - coordinates: Optional["StreampostsfirehosekoResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataGeoCoordinates(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataNoteTweet(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataNoteTweet""" - - entities: Optional["StreampostsfirehosekoResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataOrganicMetrics(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataPromotedMetrics(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataPublicMetrics(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataScopes(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataScopes""" - - followers: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseDataWithheld(BaseModel): - """Nested model for StreampostsfirehosekoResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosekoResponseIncludes(BaseModel): - """Nested model for StreampostsfirehosekoResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamPosts - - -class StreampostsResponse(BaseModel): - """Response model for streamPosts""" - - data: Optional["StreampostsResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreampostsResponseIncludes"] = None - matching_rules: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseData(BaseModel): - """Nested model for StreampostsResponseData""" - - attachments: Optional["StreampostsResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreampostsResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreampostsResponseDataEntities"] = None - geo: Optional["StreampostsResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional["StreampostsResponseDataNonPublicMetrics"] = None - note_tweet: Optional["StreampostsResponseDataNoteTweet"] = None - organic_metrics: Optional["StreampostsResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreampostsResponseDataPromotedMetrics"] = None - public_metrics: Optional["StreampostsResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreampostsResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreampostsResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataAttachments(BaseModel): - """Nested model for StreampostsResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataEditControls(BaseModel): - """Nested model for StreampostsResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataEntities(BaseModel): - """Nested model for StreampostsResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataGeo(BaseModel): - """Nested model for StreampostsResponseDataGeo""" - - coordinates: Optional["StreampostsResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataGeoCoordinates(BaseModel): - """Nested model for StreampostsResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreampostsResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataNoteTweet(BaseModel): - """Nested model for StreampostsResponseDataNoteTweet""" - - entities: Optional["StreampostsResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreampostsResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataOrganicMetrics(BaseModel): - """Nested model for StreampostsResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataPromotedMetrics(BaseModel): - """Nested model for StreampostsResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataPublicMetrics(BaseModel): - """Nested model for StreampostsResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataScopes(BaseModel): - """Nested model for StreampostsResponseDataScopes""" - - followers: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseDataWithheld(BaseModel): - """Nested model for StreampostsResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsResponseIncludes(BaseModel): - """Nested model for StreampostsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getPostsQuotedPosts - - -class GetpostsquotedpostsResponse(BaseModel): - """Response model for getPostsQuotedPosts""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetpostsquotedpostsResponseIncludes"] = None - meta: Optional["GetpostsquotedpostsResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsquotedpostsResponseIncludes(BaseModel): - """Nested model for GetpostsquotedpostsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsquotedpostsResponseMeta(BaseModel): - """Nested model for GetpostsquotedpostsResponseMeta""" - - next_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersMentions - - -class GetusersmentionsResponse(BaseModel): - """Response model for getUsersMentions""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetusersmentionsResponseIncludes"] = None - meta: Optional["GetusersmentionsResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersmentionsResponseIncludes(BaseModel): - """Nested model for GetusersmentionsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersmentionsResponseMeta(BaseModel): - """Nested model for GetusersmentionsResponseMeta""" - - newest_id: Optional[str] = None - next_token: Optional[str] = None - oldest_id: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for unlikePost - - -class UnlikepostResponse(BaseModel): - """Response model for unlikePost""" - - data: Optional["UnlikepostResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class UnlikepostResponseData(BaseModel): - """Nested model for UnlikepostResponseData""" - - liked: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getPostsById - - -class GetpostsbyidResponse(BaseModel): - """Response model for getPostsById""" - - data: Optional["GetpostsbyidResponseData"] = None - errors: Optional[List] = None - includes: Optional["GetpostsbyidResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsbyidResponseData(BaseModel): - """Nested model for GetpostsbyidResponseData""" - - attachments: Optional["GetpostsbyidResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["GetpostsbyidResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["GetpostsbyidResponseDataEntities"] = None - geo: Optional["GetpostsbyidResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional["GetpostsbyidResponseDataNonPublicMetrics"] = None - note_tweet: Optional["GetpostsbyidResponseDataNoteTweet"] = None - organic_metrics: Optional["GetpostsbyidResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["GetpostsbyidResponseDataPromotedMetrics"] = None - public_metrics: Optional["GetpostsbyidResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["GetpostsbyidResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["GetpostsbyidResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsbyidResponseDataAttachments(BaseModel): - """Nested model for GetpostsbyidResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsbyidResponseDataEditControls(BaseModel): - """Nested model for GetpostsbyidResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsbyidResponseDataEntities(BaseModel): - """Nested model for GetpostsbyidResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsbyidResponseDataGeo(BaseModel): - """Nested model for GetpostsbyidResponseDataGeo""" - - coordinates: Optional["GetpostsbyidResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsbyidResponseDataGeoCoordinates(BaseModel): - """Nested model for GetpostsbyidResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsbyidResponseDataNonPublicMetrics(BaseModel): - """Nested model for GetpostsbyidResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsbyidResponseDataNoteTweet(BaseModel): - """Nested model for GetpostsbyidResponseDataNoteTweet""" - - entities: Optional["GetpostsbyidResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsbyidResponseDataNoteTweetEntities(BaseModel): - """Nested model for GetpostsbyidResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsbyidResponseDataOrganicMetrics(BaseModel): - """Nested model for GetpostsbyidResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsbyidResponseDataPromotedMetrics(BaseModel): - """Nested model for GetpostsbyidResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsbyidResponseDataPublicMetrics(BaseModel): - """Nested model for GetpostsbyidResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsbyidResponseDataScopes(BaseModel): - """Nested model for GetpostsbyidResponseDataScopes""" - - followers: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsbyidResponseDataWithheld(BaseModel): - """Nested model for GetpostsbyidResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsbyidResponseIncludes(BaseModel): - """Nested model for GetpostsbyidResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for deletePosts - - -class DeletepostsResponse(BaseModel): - """Response model for deletePosts""" - - data: Optional["DeletepostsResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class DeletepostsResponseData(BaseModel): - """Nested model for DeletepostsResponseData""" - - deleted: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for searchPostsAll - - -class SearchpostsallResponse(BaseModel): - """Response model for searchPostsAll""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["SearchpostsallResponseIncludes"] = None - meta: Optional["SearchpostsallResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class SearchpostsallResponseIncludes(BaseModel): - """Nested model for SearchpostsallResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class SearchpostsallResponseMeta(BaseModel): - """Nested model for SearchpostsallResponseMeta""" - - newest_id: Optional[str] = None - next_token: Optional[str] = None - oldest_id: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for hidePostsReply - - -class HidepostsreplyRequest(BaseModel): - """Request model for hidePostsReply""" - - hidden: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class HidepostsreplyResponse(BaseModel): - """Response model for hidePostsReply""" - - data: Optional["HidepostsreplyResponseData"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class HidepostsreplyResponseData(BaseModel): - """Nested model for HidepostsreplyResponseData""" - - hidden: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamPostsSample - - -class StreampostssampleResponse(BaseModel): - """Response model for streamPostsSample""" - - data: Optional["StreampostssampleResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreampostssampleResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseData(BaseModel): - """Nested model for StreampostssampleResponseData""" - - attachments: Optional["StreampostssampleResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreampostssampleResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreampostssampleResponseDataEntities"] = None - geo: Optional["StreampostssampleResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional["StreampostssampleResponseDataNonPublicMetrics"] = None - note_tweet: Optional["StreampostssampleResponseDataNoteTweet"] = None - organic_metrics: Optional["StreampostssampleResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreampostssampleResponseDataPromotedMetrics"] = None - public_metrics: Optional["StreampostssampleResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreampostssampleResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreampostssampleResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataAttachments(BaseModel): - """Nested model for StreampostssampleResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataEditControls(BaseModel): - """Nested model for StreampostssampleResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataEntities(BaseModel): - """Nested model for StreampostssampleResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataGeo(BaseModel): - """Nested model for StreampostssampleResponseDataGeo""" - - coordinates: Optional["StreampostssampleResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataGeoCoordinates(BaseModel): - """Nested model for StreampostssampleResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreampostssampleResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataNoteTweet(BaseModel): - """Nested model for StreampostssampleResponseDataNoteTweet""" - - entities: Optional["StreampostssampleResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreampostssampleResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataOrganicMetrics(BaseModel): - """Nested model for StreampostssampleResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataPromotedMetrics(BaseModel): - """Nested model for StreampostssampleResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataPublicMetrics(BaseModel): - """Nested model for StreampostssampleResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataScopes(BaseModel): - """Nested model for StreampostssampleResponseDataScopes""" - - followers: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseDataWithheld(BaseModel): - """Nested model for StreampostssampleResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostssampleResponseIncludes(BaseModel): - """Nested model for StreampostssampleResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersTimeline - - -class GetuserstimelineResponse(BaseModel): - """Response model for getUsersTimeline""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetuserstimelineResponseIncludes"] = None - meta: Optional["GetuserstimelineResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetuserstimelineResponseIncludes(BaseModel): - """Nested model for GetuserstimelineResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetuserstimelineResponseMeta(BaseModel): - """Nested model for GetuserstimelineResponseMeta""" - - newest_id: Optional[str] = None - next_token: Optional[str] = None - oldest_id: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersPosts - - -class GetuserspostsResponse(BaseModel): - """Response model for getUsersPosts""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetuserspostsResponseIncludes"] = None - meta: Optional["GetuserspostsResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetuserspostsResponseIncludes(BaseModel): - """Nested model for GetuserspostsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetuserspostsResponseMeta(BaseModel): - """Nested model for GetuserspostsResponseMeta""" - - newest_id: Optional[str] = None - next_token: Optional[str] = None - oldest_id: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getSpacesBuyers - - -class GetspacesbuyersResponse(BaseModel): - """Response model for getSpacesBuyers""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetspacesbuyersResponseIncludes"] = None - meta: Optional["GetspacesbuyersResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetspacesbuyersResponseIncludes(BaseModel): - """Nested model for GetspacesbuyersResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetspacesbuyersResponseMeta(BaseModel): - """Nested model for GetspacesbuyersResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for repostPost - - -class RepostpostRequest(BaseModel): - """Request model for repostPost""" - - tweet_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class RepostpostResponse(BaseModel): - """Response model for repostPost""" - - data: Optional["RepostpostResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class RepostpostResponseData(BaseModel): - """Nested model for RepostpostResponseData""" - - id: Optional[str] = None - retweeted: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getInsights28Hr - - -class Getinsights28hrResponse(BaseModel): - """Response model for getInsights28Hr""" - - data: Optional[List] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getPostsByIds - - -class GetpostsbyidsResponse(BaseModel): - """Response model for getPostsByIds""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetpostsbyidsResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsbyidsResponseIncludes(BaseModel): - """Nested model for GetpostsbyidsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for createPosts - - -class CreatepostsRequest(BaseModel): - """Request model for createPosts""" - - card_uri: Optional[str] = None - community_id: Optional[str] = None - direct_message_deep_link: Optional[str] = None - for_super_followers_only: Optional[bool] = None - geo: Optional["CreatepostsRequestGeo"] = None - media: Optional["CreatepostsRequestMedia"] = Field( - description="Media information being attached to created Tweet. This is mutually exclusive from Quote Tweet Id, Poll, and Card URI.", - default_factory=dict, - ) - nullcast: Optional[bool] = None - poll: Optional["CreatepostsRequestPoll"] = Field( - description="Poll options for a Tweet with a poll. This is mutually exclusive from Media, Quote Tweet Id, and Card URI.", - default_factory=dict, - ) - quote_tweet_id: Optional[str] = None - reply: Optional["CreatepostsRequestReply"] = Field( - description="Tweet information of the Tweet being replied to.", - default_factory=dict, - ) - reply_settings: Optional[str] = None - share_with_followers: Optional[bool] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatepostsResponse(BaseModel): - """Response model for createPosts""" - - data: Optional["CreatepostsResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatepostsRequestGeo(BaseModel): - """Nested model for CreatepostsRequestGeo""" - - place_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatepostsRequestMedia(BaseModel): - """Nested model for CreatepostsRequestMedia""" - - media_ids: Optional[List] = None - tagged_user_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatepostsRequestPoll(BaseModel): - """Nested model for CreatepostsRequestPoll""" - - duration_minutes: Optional[int] = None - options: Optional[List] = None - reply_settings: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatepostsRequestReply(BaseModel): - """Nested model for CreatepostsRequestReply""" - - exclude_reply_user_ids: Optional[List] = None - in_reply_to_tweet_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatepostsResponseData(BaseModel): - """Nested model for CreatepostsResponseData""" - - id: Optional[str] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersLikedPosts - - -class GetuserslikedpostsResponse(BaseModel): - """Response model for getUsersLikedPosts""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetuserslikedpostsResponseIncludes"] = None - meta: Optional["GetuserslikedpostsResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetuserslikedpostsResponseIncludes(BaseModel): - """Nested model for GetuserslikedpostsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetuserslikedpostsResponseMeta(BaseModel): - """Nested model for GetuserslikedpostsResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getInsightsHistorical - - -class GetinsightshistoricalResponse(BaseModel): - """Response model for getInsightsHistorical""" - - data: Optional[List] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamPostsFirehoseJa - - -class StreampostsfirehosejaResponse(BaseModel): - """Response model for streamPostsFirehoseJa""" - - data: Optional["StreampostsfirehosejaResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreampostsfirehosejaResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseData(BaseModel): - """Nested model for StreampostsfirehosejaResponseData""" - - attachments: Optional["StreampostsfirehosejaResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreampostsfirehosejaResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreampostsfirehosejaResponseDataEntities"] = None - geo: Optional["StreampostsfirehosejaResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional[ - "StreampostsfirehosejaResponseDataNonPublicMetrics" - ] = None - note_tweet: Optional["StreampostsfirehosejaResponseDataNoteTweet"] = None - organic_metrics: Optional["StreampostsfirehosejaResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreampostsfirehosejaResponseDataPromotedMetrics"] = ( - None - ) - public_metrics: Optional["StreampostsfirehosejaResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreampostsfirehosejaResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreampostsfirehosejaResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataAttachments(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataEditControls(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataEntities(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataGeo(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataGeo""" - - coordinates: Optional["StreampostsfirehosejaResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataGeoCoordinates(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataNoteTweet(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataNoteTweet""" - - entities: Optional["StreampostsfirehosejaResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataOrganicMetrics(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataPromotedMetrics(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataPublicMetrics(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataScopes(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataScopes""" - - followers: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseDataWithheld(BaseModel): - """Nested model for StreampostsfirehosejaResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehosejaResponseIncludes(BaseModel): - """Nested model for StreampostsfirehosejaResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for streamPostsFirehosePt - - -class StreampostsfirehoseptResponse(BaseModel): - """Response model for streamPostsFirehosePt""" - - data: Optional["StreampostsfirehoseptResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreampostsfirehoseptResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseData(BaseModel): - """Nested model for StreampostsfirehoseptResponseData""" - - attachments: Optional["StreampostsfirehoseptResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreampostsfirehoseptResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreampostsfirehoseptResponseDataEntities"] = None - geo: Optional["StreampostsfirehoseptResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional[ - "StreampostsfirehoseptResponseDataNonPublicMetrics" - ] = None - note_tweet: Optional["StreampostsfirehoseptResponseDataNoteTweet"] = None - organic_metrics: Optional["StreampostsfirehoseptResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreampostsfirehoseptResponseDataPromotedMetrics"] = ( - None - ) - public_metrics: Optional["StreampostsfirehoseptResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreampostsfirehoseptResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreampostsfirehoseptResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataAttachments(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataEditControls(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataEntities(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataGeo(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataGeo""" - - coordinates: Optional["StreampostsfirehoseptResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataGeoCoordinates(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataNoteTweet(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataNoteTweet""" - - entities: Optional["StreampostsfirehoseptResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataOrganicMetrics(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataPromotedMetrics(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataPublicMetrics(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataScopes(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataScopes""" - - followers: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseDataWithheld(BaseModel): - """Nested model for StreampostsfirehoseptResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class StreampostsfirehoseptResponseIncludes(BaseModel): - """Nested model for StreampostsfirehoseptResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for unrepostPost - - -class UnrepostpostResponse(BaseModel): - """Response model for unrepostPost""" - - data: Optional["UnrepostpostResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class UnrepostpostResponseData(BaseModel): - """Nested model for UnrepostpostResponseData""" - - retweeted: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getPostsReposts - - -class GetpostsrepostsResponse(BaseModel): - """Response model for getPostsReposts""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetpostsrepostsResponseIncludes"] = None - meta: Optional["GetpostsrepostsResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsrepostsResponseIncludes(BaseModel): - """Nested model for GetpostsrepostsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsrepostsResponseMeta(BaseModel): - """Nested model for GetpostsrepostsResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getRules - - -class GetrulesResponse(BaseModel): - """Response model for getRules""" - - data: Optional[List] = None - meta: Optional["GetrulesResponseMeta"] = Field(default_factory=dict) - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetrulesResponseMeta(BaseModel): - """Nested model for GetrulesResponseMeta""" - - next_token: Optional[str] = None - result_count: Optional[int] = None - sent: Optional[str] = None - summary: Any = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for updateRules - - -class UpdaterulesRequest(BaseModel): - """Request model for updateRules""" - - add: Optional[List] = Field(default=None) - delete: Optional[Dict[str, Any]] = Field( - default=None, - description="IDs and values of all deleted user-specified stream filtering rules.", - ) - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class UpdaterulesResponse(BaseModel): - """Response model for updateRules""" - - data: Optional[List] = None - errors: Optional[List] = None - meta: Optional["UpdaterulesResponseMeta"] = Field(default_factory=dict) - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class UpdaterulesResponseMeta(BaseModel): - """Nested model for UpdaterulesResponseMeta""" - - next_token: Optional[str] = None - result_count: Optional[int] = None - sent: Optional[str] = None - summary: Any = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/python/xdk/usage/__init__.py b/xdk/python/xdk/python/xdk/usage/__init__.py deleted file mode 100644 index 2502c9de..00000000 --- a/xdk/python/xdk/python/xdk/usage/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Usage module for the X API. - -This module provides access to the Usage endpoints of the X API. -""" - -from .client import UsageClient - -__all__ = ["UsageClient"] diff --git a/xdk/python/xdk/python/xdk/usage/client.py b/xdk/python/xdk/python/xdk/usage/client.py deleted file mode 100644 index 02bde530..00000000 --- a/xdk/python/xdk/python/xdk/usage/client.py +++ /dev/null @@ -1,68 +0,0 @@ -""" -Usage client for the X API. - -This module provides a client for interacting with the Usage endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - GetusageResponse, -) - - -class UsageClient: - """Client for Usage operations""" - - - def __init__(self, client: Client): - self.client = client - - - def get_usage( - self, - days: int = None, - usage_fields: List = None, - ) -> GetusageResponse: - """ - Get usage - Retrieves usage statistics for Posts over a specified number of days. - Args: - days: The number of days for which you need usage for. - Args: - usage_fields: A comma separated list of Usage fields to display. - Returns: - GetusageResponse: Response data - """ - url = self.client.base_url + "/2/usage/tweets" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if days is not None: - params["days"] = days - if usage_fields is not None: - params["usage.fields"] = ",".join(str(item) for item in usage_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetusageResponse.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/usage/models.py b/xdk/python/xdk/python/xdk/usage/models.py deleted file mode 100644 index e858019e..00000000 --- a/xdk/python/xdk/python/xdk/usage/models.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -Usage models for the X API. - -This module provides models for the Usage endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for getUsage - - -class GetusageResponse(BaseModel): - """Response model for getUsage""" - - data: Optional["GetusageResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusageResponseData(BaseModel): - """Nested model for GetusageResponseData""" - - cap_reset_day: Optional[int] = None - daily_client_app_usage: Optional[List] = None - daily_project_usage: Optional["GetusageResponseDataDailyProjectUsage"] = None - project_cap: Optional[int] = None - project_id: Optional[str] = None - project_usage: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusageResponseDataDailyProjectUsage(BaseModel): - """Nested model for GetusageResponseDataDailyProjectUsage""" - - project_id: Optional[int] = None - usage: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/python/xdk/users/__init__.py b/xdk/python/xdk/python/xdk/users/__init__.py deleted file mode 100644 index f316d37d..00000000 --- a/xdk/python/xdk/python/xdk/users/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Users module for the X API. - -This module provides access to the Users endpoints of the X API. -""" - -from .client import UsersClient - -__all__ = ["UsersClient"] diff --git a/xdk/python/xdk/python/xdk/users/client.py b/xdk/python/xdk/python/xdk/users/client.py deleted file mode 100644 index 79dcc66f..00000000 --- a/xdk/python/xdk/python/xdk/users/client.py +++ /dev/null @@ -1,1293 +0,0 @@ -""" -Users client for the X API. - -This module provides a client for interacting with the Users endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - GetusersblockingResponse, - GetlistsmembersResponse, - GetusersbyusernamesResponse, - GetusersrepostsofmeResponse, - SearchusersResponse, - GetusersfollowersResponse, - GetusersfollowingResponse, - FollowuserRequest, - FollowuserResponse, - GetpostslikingusersResponse, - GetpostsrepostedbyResponse, - GetusersbyidResponse, - GetusersbyidsResponse, - GetmyuserResponse, - GetlistsfollowersResponse, - BlockusersdmsResponse, - UnblockusersdmsResponse, - GetusersmutingResponse, - MuteuserRequest, - MuteuserResponse, - UnfollowuserResponse, - UnmuteuserResponse, - GetusersbyusernameResponse, -) - - -class UsersClient: - """Client for Users operations""" - - - def __init__(self, client: Client): - self.client = client - - - def get_users_blocking( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetusersblockingResponse: - """ - Get blocking - Retrieves a list of Users blocked by the specified User ID. - Args: - id: The ID of the authenticated source User for whom to return results. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetusersblockingResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/blocking" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetusersblockingResponse.model_validate(response_data) - - - def get_lists_members( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetlistsmembersResponse: - """ - Get List members - Retrieves a list of Users who are members of a specific List by its ID. - Args: - id: The ID of the List. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetlistsmembersResponse: Response data - """ - url = self.client.base_url + "/2/lists/{id}/members" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetlistsmembersResponse.model_validate(response_data) - - - def get_users_by_usernames( - self, - usernames: List, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetusersbyusernamesResponse: - """ - Get Users by usernames - Retrieves details of multiple Users by their usernames. - Args: - usernames: A list of usernames, comma-separated. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetusersbyusernamesResponse: Response data - """ - url = self.client.base_url + "/2/users/by" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if usernames is not None: - params["usernames"] = ",".join(str(item) for item in usernames) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetusersbyusernamesResponse.model_validate(response_data) - - - def get_users_reposts_of_me( - self, - max_results: int = None, - pagination_token: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetusersrepostsofmeResponse: - """ - Get Reposts of me - Retrieves a list of Posts that repost content from the authenticated user. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetusersrepostsofmeResponse: Response data - """ - url = self.client.base_url + "/2/users/reposts_of_me" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetusersrepostsofmeResponse.model_validate(response_data) - - - def search_users( - self, - query: str, - max_results: int = None, - next_token: str = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> SearchusersResponse: - """ - Search Users - Retrieves a list of Users matching a search query. - Args: - query: TThe the query string by which to query for users. - Args: - max_results: The maximum number of results. - Args: - next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - SearchusersResponse: Response data - """ - url = self.client.base_url + "/2/users/search" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if query is not None: - params["query"] = query - if max_results is not None: - params["max_results"] = max_results - if next_token is not None: - params["next_token"] = next_token - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return SearchusersResponse.model_validate(response_data) - - - def get_users_followers( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetusersfollowersResponse: - """ - Get followers - Retrieves a list of Users who follow a specific User by their ID. - Args: - id: The ID of the User to lookup. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetusersfollowersResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/followers" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetusersfollowersResponse.model_validate(response_data) - - - def get_users_following( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetusersfollowingResponse: - """ - Get following - Retrieves a list of Users followed by a specific User by their ID. - Args: - id: The ID of the User to lookup. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetusersfollowingResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/following" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetusersfollowingResponse.model_validate(response_data) - - - def follow_user( - self, - id: str, - body: Optional[FollowuserRequest] = None, - ) -> FollowuserResponse: - """ - Follow User - Causes the authenticated user to follow a specific user by their ID. - Args: - id: The ID of the authenticated source User that is requesting to follow the target User. - body: Request body - Returns: - FollowuserResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/following" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return FollowuserResponse.model_validate(response_data) - - - def get_posts_liking_users( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetpostslikingusersResponse: - """ - Get Liking Users - Retrieves a list of Users who liked a specific Post by its ID. - Args: - id: A single Post ID. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetpostslikingusersResponse: Response data - """ - url = self.client.base_url + "/2/tweets/{id}/liking_users" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetpostslikingusersResponse.model_validate(response_data) - - - def get_posts_reposted_by( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetpostsrepostedbyResponse: - """ - Get Reposted by - Retrieves a list of Users who reposted a specific Post by its ID. - Args: - id: A single Post ID. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetpostsrepostedbyResponse: Response data - """ - url = self.client.base_url + "/2/tweets/{id}/retweeted_by" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetpostsrepostedbyResponse.model_validate(response_data) - - - def get_users_by_id( - self, - id: str, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetusersbyidResponse: - """ - Get User by ID - Retrieves details of a specific User by their ID. - Args: - id: The ID of the User to lookup. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetusersbyidResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetusersbyidResponse.model_validate(response_data) - - - def get_users_by_ids( - self, - ids: List, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetusersbyidsResponse: - """ - Get Users by IDs - Retrieves details of multiple Users by their IDs. - Args: - ids: A list of User IDs, comma-separated. You can specify up to 100 IDs. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetusersbyidsResponse: Response data - """ - url = self.client.base_url + "/2/users" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if ids is not None: - params["ids"] = ",".join(str(item) for item in ids) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetusersbyidsResponse.model_validate(response_data) - - - def get_my_user( - self, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetmyuserResponse: - """ - Get my User - Retrieves details of the authenticated user. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetmyuserResponse: Response data - """ - url = self.client.base_url + "/2/users/me" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetmyuserResponse.model_validate(response_data) - - - def get_lists_followers( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetlistsfollowersResponse: - """ - Get List followers - Retrieves a list of Users who follow a specific List by its ID. - Args: - id: The ID of the List. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetlistsfollowersResponse: Response data - """ - url = self.client.base_url + "/2/lists/{id}/followers" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetlistsfollowersResponse.model_validate(response_data) - - - def block_users_dms( - self, - id: str, - ) -> BlockusersdmsResponse: - """ - Block DMs - Blocks direct messages to or from a specific User by their ID for the authenticated user. - Args: - id: The ID of the target User that the authenticated user requesting to block dms for. - Returns: - BlockusersdmsResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/dm/block" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return BlockusersdmsResponse.model_validate(response_data) - - - def unblock_users_dms( - self, - id: str, - ) -> UnblockusersdmsResponse: - """ - Unblock DMs - Unblocks direct messages to or from a specific User by their ID for the authenticated user. - Args: - id: The ID of the target User that the authenticated user requesting to unblock dms for. - Returns: - UnblockusersdmsResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/dm/unblock" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return UnblockusersdmsResponse.model_validate(response_data) - - - def get_users_muting( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetusersmutingResponse: - """ - Get muting - Retrieves a list of Users muted by the authenticated user. - Args: - id: The ID of the authenticated source User for whom to return results. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetusersmutingResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/muting" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetusersmutingResponse.model_validate(response_data) - - - def mute_user( - self, - id: str, - body: Optional[MuteuserRequest] = None, - ) -> MuteuserResponse: - """ - Mute User - Causes the authenticated user to mute a specific User by their ID. - Args: - id: The ID of the authenticated source User that is requesting to mute the target User. - body: Request body - Returns: - MuteuserResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/muting" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return MuteuserResponse.model_validate(response_data) - - - def unfollow_user( - self, - source_user_id: str, - target_user_id: str, - ) -> UnfollowuserResponse: - """ - Unfollow User - Causes the authenticated user to unfollow a specific user by their ID. - Args: - source_user_id: The ID of the authenticated source User that is requesting to unfollow the target User. - Args: - target_user_id: The ID of the User that the source User is requesting to unfollow. - Returns: - UnfollowuserResponse: Response data - """ - url = ( - self.client.base_url - + "/2/users/{source_user_id}/following/{target_user_id}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{source_user_id}", str(source_user_id)) - url = url.replace("{target_user_id}", str(target_user_id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.delete( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.delete( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return UnfollowuserResponse.model_validate(response_data) - - - def unmute_user( - self, - source_user_id: str, - target_user_id: str, - ) -> UnmuteuserResponse: - """ - Unmute User - Causes the authenticated user to unmute a specific user by their ID. - Args: - source_user_id: The ID of the authenticated source User that is requesting to unmute the target User. - Args: - target_user_id: The ID of the User that the source User is requesting to unmute. - Returns: - UnmuteuserResponse: Response data - """ - url = self.client.base_url + "/2/users/{source_user_id}/muting/{target_user_id}" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{source_user_id}", str(source_user_id)) - url = url.replace("{target_user_id}", str(target_user_id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.delete( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.delete( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return UnmuteuserResponse.model_validate(response_data) - - - def get_users_by_username( - self, - username: str, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetusersbyusernameResponse: - """ - Get User by username - Retrieves details of a specific User by their username. - Args: - username: A username. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetusersbyusernameResponse: Response data - """ - url = self.client.base_url + "/2/users/by/username/{username}" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{username}", str(username)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetusersbyusernameResponse.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/users/models.py b/xdk/python/xdk/python/xdk/users/models.py deleted file mode 100644 index 7602d688..00000000 --- a/xdk/python/xdk/python/xdk/users/models.py +++ /dev/null @@ -1,1143 +0,0 @@ -""" -Users models for the X API. - -This module provides models for the Users endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for getUsersBlocking - - -class GetusersblockingResponse(BaseModel): - """Response model for getUsersBlocking""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetusersblockingResponseIncludes"] = None - meta: Optional["GetusersblockingResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersblockingResponseIncludes(BaseModel): - """Nested model for GetusersblockingResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersblockingResponseMeta(BaseModel): - """Nested model for GetusersblockingResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getListsMembers - - -class GetlistsmembersResponse(BaseModel): - """Response model for getListsMembers""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetlistsmembersResponseIncludes"] = None - meta: Optional["GetlistsmembersResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetlistsmembersResponseIncludes(BaseModel): - """Nested model for GetlistsmembersResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetlistsmembersResponseMeta(BaseModel): - """Nested model for GetlistsmembersResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersByUsernames - - -class GetusersbyusernamesResponse(BaseModel): - """Response model for getUsersByUsernames""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetusersbyusernamesResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbyusernamesResponseIncludes(BaseModel): - """Nested model for GetusersbyusernamesResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersRepostsOfMe - - -class GetusersrepostsofmeResponse(BaseModel): - """Response model for getUsersRepostsOfMe""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetusersrepostsofmeResponseIncludes"] = None - meta: Optional["GetusersrepostsofmeResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersrepostsofmeResponseIncludes(BaseModel): - """Nested model for GetusersrepostsofmeResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersrepostsofmeResponseMeta(BaseModel): - """Nested model for GetusersrepostsofmeResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for searchUsers - - -class SearchusersResponse(BaseModel): - """Response model for searchUsers""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["SearchusersResponseIncludes"] = None - meta: Optional["SearchusersResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class SearchusersResponseIncludes(BaseModel): - """Nested model for SearchusersResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class SearchusersResponseMeta(BaseModel): - """Nested model for SearchusersResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersFollowers - - -class GetusersfollowersResponse(BaseModel): - """Response model for getUsersFollowers""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetusersfollowersResponseIncludes"] = None - meta: Optional["GetusersfollowersResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersfollowersResponseIncludes(BaseModel): - """Nested model for GetusersfollowersResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersfollowersResponseMeta(BaseModel): - """Nested model for GetusersfollowersResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersFollowing - - -class GetusersfollowingResponse(BaseModel): - """Response model for getUsersFollowing""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetusersfollowingResponseIncludes"] = None - meta: Optional["GetusersfollowingResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersfollowingResponseIncludes(BaseModel): - """Nested model for GetusersfollowingResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersfollowingResponseMeta(BaseModel): - """Nested model for GetusersfollowingResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for followUser - - -class FollowuserRequest(BaseModel): - """Request model for followUser""" - - target_user_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class FollowuserResponse(BaseModel): - """Response model for followUser""" - - data: Optional["FollowuserResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class FollowuserResponseData(BaseModel): - """Nested model for FollowuserResponseData""" - - following: Optional[bool] = None - pending_follow: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getPostsLikingUsers - - -class GetpostslikingusersResponse(BaseModel): - """Response model for getPostsLikingUsers""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetpostslikingusersResponseIncludes"] = None - meta: Optional["GetpostslikingusersResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostslikingusersResponseIncludes(BaseModel): - """Nested model for GetpostslikingusersResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostslikingusersResponseMeta(BaseModel): - """Nested model for GetpostslikingusersResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getPostsRepostedBy - - -class GetpostsrepostedbyResponse(BaseModel): - """Response model for getPostsRepostedBy""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetpostsrepostedbyResponseIncludes"] = None - meta: Optional["GetpostsrepostedbyResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsrepostedbyResponseIncludes(BaseModel): - """Nested model for GetpostsrepostedbyResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetpostsrepostedbyResponseMeta(BaseModel): - """Nested model for GetpostsrepostedbyResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersById - - -class GetusersbyidResponse(BaseModel): - """Response model for getUsersById""" - - data: Optional["GetusersbyidResponseData"] = Field( - description="The X User object.", default_factory=dict - ) - errors: Optional[List] = None - includes: Optional["GetusersbyidResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbyidResponseData(BaseModel): - """Nested model for GetusersbyidResponseData""" - - affiliation: Optional["GetusersbyidResponseDataAffiliation"] = None - connection_status: Optional[List] = None - created_at: Optional[str] = None - description: Optional[str] = None - entities: Optional["GetusersbyidResponseDataEntities"] = None - id: Optional[str] = None - location: Optional[str] = None - most_recent_tweet_id: Optional[str] = None - name: Optional[str] = None - pinned_tweet_id: Optional[str] = None - profile_banner_url: Optional[str] = None - profile_image_url: Optional[str] = None - protected: Optional[bool] = None - public_metrics: Optional["GetusersbyidResponseDataPublicMetrics"] = None - receives_your_dm: Optional[bool] = None - subscription_type: Optional[str] = None - url: Optional[str] = None - username: Optional[str] = None - verified: Optional[bool] = None - verified_type: Optional[str] = None - withheld: Optional["GetusersbyidResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbyidResponseDataAffiliation(BaseModel): - """Nested model for GetusersbyidResponseDataAffiliation""" - - badge_url: Optional[str] = None - description: Optional[str] = None - url: Optional[str] = None - user_id: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbyidResponseDataEntities(BaseModel): - """Nested model for GetusersbyidResponseDataEntities""" - - description: Optional["GetusersbyidResponseDataEntitiesDescription"] = None - url: Optional["GetusersbyidResponseDataEntitiesUrl"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbyidResponseDataEntitiesDescription(BaseModel): - """Nested model for GetusersbyidResponseDataEntitiesDescription""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbyidResponseDataEntitiesUrl(BaseModel): - """Nested model for GetusersbyidResponseDataEntitiesUrl""" - - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbyidResponseDataPublicMetrics(BaseModel): - """Nested model for GetusersbyidResponseDataPublicMetrics""" - - followers_count: Optional[int] = None - following_count: Optional[int] = None - like_count: Optional[int] = None - listed_count: Optional[int] = None - tweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbyidResponseDataWithheld(BaseModel): - """Nested model for GetusersbyidResponseDataWithheld""" - - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbyidResponseIncludes(BaseModel): - """Nested model for GetusersbyidResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersByIds - - -class GetusersbyidsResponse(BaseModel): - """Response model for getUsersByIds""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetusersbyidsResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbyidsResponseIncludes(BaseModel): - """Nested model for GetusersbyidsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getMyUser - - -class GetmyuserResponse(BaseModel): - """Response model for getMyUser""" - - data: Optional["GetmyuserResponseData"] = Field( - description="The X User object.", default_factory=dict - ) - errors: Optional[List] = None - includes: Optional["GetmyuserResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetmyuserResponseData(BaseModel): - """Nested model for GetmyuserResponseData""" - - affiliation: Optional["GetmyuserResponseDataAffiliation"] = None - connection_status: Optional[List] = None - created_at: Optional[str] = None - description: Optional[str] = None - entities: Optional["GetmyuserResponseDataEntities"] = None - id: Optional[str] = None - location: Optional[str] = None - most_recent_tweet_id: Optional[str] = None - name: Optional[str] = None - pinned_tweet_id: Optional[str] = None - profile_banner_url: Optional[str] = None - profile_image_url: Optional[str] = None - protected: Optional[bool] = None - public_metrics: Optional["GetmyuserResponseDataPublicMetrics"] = None - receives_your_dm: Optional[bool] = None - subscription_type: Optional[str] = None - url: Optional[str] = None - username: Optional[str] = None - verified: Optional[bool] = None - verified_type: Optional[str] = None - withheld: Optional["GetmyuserResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetmyuserResponseDataAffiliation(BaseModel): - """Nested model for GetmyuserResponseDataAffiliation""" - - badge_url: Optional[str] = None - description: Optional[str] = None - url: Optional[str] = None - user_id: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetmyuserResponseDataEntities(BaseModel): - """Nested model for GetmyuserResponseDataEntities""" - - description: Optional["GetmyuserResponseDataEntitiesDescription"] = None - url: Optional["GetmyuserResponseDataEntitiesUrl"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetmyuserResponseDataEntitiesDescription(BaseModel): - """Nested model for GetmyuserResponseDataEntitiesDescription""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetmyuserResponseDataEntitiesUrl(BaseModel): - """Nested model for GetmyuserResponseDataEntitiesUrl""" - - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetmyuserResponseDataPublicMetrics(BaseModel): - """Nested model for GetmyuserResponseDataPublicMetrics""" - - followers_count: Optional[int] = None - following_count: Optional[int] = None - like_count: Optional[int] = None - listed_count: Optional[int] = None - tweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetmyuserResponseDataWithheld(BaseModel): - """Nested model for GetmyuserResponseDataWithheld""" - - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetmyuserResponseIncludes(BaseModel): - """Nested model for GetmyuserResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getListsFollowers - - -class GetlistsfollowersResponse(BaseModel): - """Response model for getListsFollowers""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetlistsfollowersResponseIncludes"] = None - meta: Optional["GetlistsfollowersResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetlistsfollowersResponseIncludes(BaseModel): - """Nested model for GetlistsfollowersResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetlistsfollowersResponseMeta(BaseModel): - """Nested model for GetlistsfollowersResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for blockUsersDms - - -class BlockusersdmsResponse(BaseModel): - """Response model for blockUsersDms""" - - data: Optional["BlockusersdmsResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class BlockusersdmsResponseData(BaseModel): - """Nested model for BlockusersdmsResponseData""" - - blocked: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for unblockUsersDms - - -class UnblockusersdmsResponse(BaseModel): - """Response model for unblockUsersDms""" - - data: Optional["UnblockusersdmsResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class UnblockusersdmsResponseData(BaseModel): - """Nested model for UnblockusersdmsResponseData""" - - blocked: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersMuting - - -class GetusersmutingResponse(BaseModel): - """Response model for getUsersMuting""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetusersmutingResponseIncludes"] = None - meta: Optional["GetusersmutingResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersmutingResponseIncludes(BaseModel): - """Nested model for GetusersmutingResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersmutingResponseMeta(BaseModel): - """Nested model for GetusersmutingResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for muteUser - - -class MuteuserRequest(BaseModel): - """Request model for muteUser""" - - target_user_id: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class MuteuserResponse(BaseModel): - """Response model for muteUser""" - - data: Optional["MuteuserResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class MuteuserResponseData(BaseModel): - """Nested model for MuteuserResponseData""" - - muting: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for unfollowUser - - -class UnfollowuserResponse(BaseModel): - """Response model for unfollowUser""" - - data: Optional["UnfollowuserResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class UnfollowuserResponseData(BaseModel): - """Nested model for UnfollowuserResponseData""" - - following: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for unmuteUser - - -class UnmuteuserResponse(BaseModel): - """Response model for unmuteUser""" - - data: Optional["UnmuteuserResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class UnmuteuserResponseData(BaseModel): - """Nested model for UnmuteuserResponseData""" - - muting: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getUsersByUsername - - -class GetusersbyusernameResponse(BaseModel): - """Response model for getUsersByUsername""" - - data: Optional["GetusersbyusernameResponseData"] = Field( - description="The X User object.", default_factory=dict - ) - errors: Optional[List] = None - includes: Optional["GetusersbyusernameResponseIncludes"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbyusernameResponseData(BaseModel): - """Nested model for GetusersbyusernameResponseData""" - - affiliation: Optional["GetusersbyusernameResponseDataAffiliation"] = None - connection_status: Optional[List] = None - created_at: Optional[str] = None - description: Optional[str] = None - entities: Optional["GetusersbyusernameResponseDataEntities"] = None - id: Optional[str] = None - location: Optional[str] = None - most_recent_tweet_id: Optional[str] = None - name: Optional[str] = None - pinned_tweet_id: Optional[str] = None - profile_banner_url: Optional[str] = None - profile_image_url: Optional[str] = None - protected: Optional[bool] = None - public_metrics: Optional["GetusersbyusernameResponseDataPublicMetrics"] = None - receives_your_dm: Optional[bool] = None - subscription_type: Optional[str] = None - url: Optional[str] = None - username: Optional[str] = None - verified: Optional[bool] = None - verified_type: Optional[str] = None - withheld: Optional["GetusersbyusernameResponseDataWithheld"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbyusernameResponseDataAffiliation(BaseModel): - """Nested model for GetusersbyusernameResponseDataAffiliation""" - - badge_url: Optional[str] = None - description: Optional[str] = None - url: Optional[str] = None - user_id: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbyusernameResponseDataEntities(BaseModel): - """Nested model for GetusersbyusernameResponseDataEntities""" - - description: Optional["GetusersbyusernameResponseDataEntitiesDescription"] = None - url: Optional["GetusersbyusernameResponseDataEntitiesUrl"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbyusernameResponseDataEntitiesDescription(BaseModel): - """Nested model for GetusersbyusernameResponseDataEntitiesDescription""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbyusernameResponseDataEntitiesUrl(BaseModel): - """Nested model for GetusersbyusernameResponseDataEntitiesUrl""" - - urls: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbyusernameResponseDataPublicMetrics(BaseModel): - """Nested model for GetusersbyusernameResponseDataPublicMetrics""" - - followers_count: Optional[int] = None - following_count: Optional[int] = None - like_count: Optional[int] = None - listed_count: Optional[int] = None - tweet_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbyusernameResponseDataWithheld(BaseModel): - """Nested model for GetusersbyusernameResponseDataWithheld""" - - country_codes: Optional[List] = None - scope: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetusersbyusernameResponseIncludes(BaseModel): - """Nested model for GetusersbyusernameResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/python/xdk/webhooks/__init__.py b/xdk/python/xdk/python/xdk/webhooks/__init__.py deleted file mode 100644 index cce446f5..00000000 --- a/xdk/python/xdk/python/xdk/webhooks/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Webhooks module for the X API. - -This module provides access to the Webhooks endpoints of the X API. -""" - -from .client import WebhooksClient - -__all__ = ["WebhooksClient"] diff --git a/xdk/python/xdk/python/xdk/webhooks/client.py b/xdk/python/xdk/python/xdk/webhooks/client.py deleted file mode 100644 index 7ede63e6..00000000 --- a/xdk/python/xdk/python/xdk/webhooks/client.py +++ /dev/null @@ -1,183 +0,0 @@ -""" -Webhooks client for the X API. - -This module provides a client for interacting with the Webhooks endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - ValidatewebhooksResponse, - DeletewebhooksResponse, - GetwebhooksResponse, - CreatewebhooksRequest, - CreatewebhooksResponse, -) - - -class WebhooksClient: - """Client for Webhooks operations""" - - - def __init__(self, client: Client): - self.client = client - - - def validate_webhooks( - self, - webhook_id: str, - ) -> ValidatewebhooksResponse: - """ - Validate webhook - Triggers a CRC check for a given webhook. - Args: - webhook_id: The ID of the webhook to check. - Returns: - ValidatewebhooksResponse: Response data - """ - url = self.client.base_url + "/2/webhooks/{webhook_id}" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - url = url.replace("{webhook_id}", str(webhook_id)) - headers = {} - # Make the request - response = self.client.session.put( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return ValidatewebhooksResponse.model_validate(response_data) - - - def delete_webhooks( - self, - webhook_id: str, - ) -> DeletewebhooksResponse: - """ - Delete webhook - Deletes an existing webhook configuration. - Args: - webhook_id: The ID of the webhook to delete. - Returns: - DeletewebhooksResponse: Response data - """ - url = self.client.base_url + "/2/webhooks/{webhook_id}" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - url = url.replace("{webhook_id}", str(webhook_id)) - headers = {} - # Make the request - response = self.client.session.delete( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return DeletewebhooksResponse.model_validate(response_data) - - - def get_webhooks( - self, - webhook_config_fields: List = None, - ) -> GetwebhooksResponse: - """ - Get webhook - Get a list of webhook configs associated with a client app. - Args: - webhook_config_fields: A comma separated list of WebhookConfig fields to display. - Returns: - GetwebhooksResponse: Response data - """ - url = self.client.base_url + "/2/webhooks" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if webhook_config_fields is not None: - params["webhook_config.fields"] = ",".join( - str(item) for item in webhook_config_fields - ) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetwebhooksResponse.model_validate(response_data) - - - def create_webhooks( - self, - body: Optional[CreatewebhooksRequest] = None, - ) -> CreatewebhooksResponse: - """ - Create webhook - Creates a new webhook configuration. - body: Request body - Returns: - CreatewebhooksResponse: Response data - """ - url = self.client.base_url + "/2/webhooks" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return CreatewebhooksResponse.model_validate(response_data) diff --git a/xdk/python/xdk/python/xdk/webhooks/models.py b/xdk/python/xdk/python/xdk/webhooks/models.py deleted file mode 100644 index da692551..00000000 --- a/xdk/python/xdk/python/xdk/webhooks/models.py +++ /dev/null @@ -1,116 +0,0 @@ -""" -Webhooks models for the X API. - -This module provides models for the Webhooks endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field -from datetime import datetime - - -# Models for validateWebhooks - - -class ValidatewebhooksResponse(BaseModel): - """Response model for validateWebhooks""" - - data: Optional["ValidatewebhooksResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class ValidatewebhooksResponseData(BaseModel): - """Nested model for ValidatewebhooksResponseData""" - - attempted: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for deleteWebhooks - - -class DeletewebhooksResponse(BaseModel): - """Response model for deleteWebhooks""" - - data: Optional["DeletewebhooksResponseData"] = None - errors: Optional[List] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class DeletewebhooksResponseData(BaseModel): - """Nested model for DeletewebhooksResponseData""" - - deleted: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for getWebhooks - - -class GetwebhooksResponse(BaseModel): - """Response model for getWebhooks""" - - data: Optional[List] = None - errors: Optional[List] = None - meta: Optional["GetwebhooksResponseMeta"] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class GetwebhooksResponseMeta(BaseModel): - """Nested model for GetwebhooksResponseMeta""" - - result_count: Optional[int] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -# Models for createWebhooks - - -class CreatewebhooksRequest(BaseModel): - """Request model for createWebhooks""" - - url: Optional[str] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True - - -class CreatewebhooksResponse(BaseModel): - """Response model for createWebhooks""" - - created_at: Optional[str] = None - id: Optional[str] = None - url: Optional[str] = None - valid: Optional[bool] = None - - class Config: - """Pydantic model configuration""" - - populate_by_name = True diff --git a/xdk/python/xdk/spaces/__init__.py b/xdk/python/xdk/spaces/__init__.py index 840cbb01..366d6c34 100644 --- a/xdk/python/xdk/spaces/__init__.py +++ b/xdk/python/xdk/spaces/__init__.py @@ -1,7 +1,7 @@ """ -Spaces module for the X API. +spaces module for the X API. -This module provides access to the Spaces endpoints of the X API. +This module provides access to the spaces endpoints of the X API. """ from .client import SpacesClient diff --git a/xdk/python/xdk/spaces/client.py b/xdk/python/xdk/spaces/client.py index c7782b38..e7a2bb78 100644 --- a/xdk/python/xdk/spaces/client.py +++ b/xdk/python/xdk/spaces/client.py @@ -1,7 +1,7 @@ """ -Spaces client for the X API. +spaces client for the X API. -This module provides a client for interacting with the Spaces endpoints of the X API. +This module provides a client for interacting with the spaces endpoints of the X API. """ from __future__ import annotations @@ -12,46 +12,86 @@ if TYPE_CHECKING: from ..client import Client from .models import ( - GetSpacesByIdResponse, - GetSpacesPostsResponse, - GetSpacesByCreatorIdsResponse, - GetSpacesBuyersResponse, - GetSpacesByIdsResponse, - SearchSpacesResponse, + GetBuyersResponse, + GetByIdResponse, + GetPostsResponse, + GetByIdsResponse, + SearchResponse, + GetByCreatorIdsResponse, ) class SpacesClient: - """Client for Spaces operations""" + """Client for spaces operations""" def __init__(self, client: Client): self.client = client - def get_spaces_by_id( + def get_buyers( self, id: str, - space_fields: List = None, - expansions: List = None, - user_fields: List = None, - topic_fields: List = None, - ) -> GetSpacesByIdResponse: + pagination_token: Any = None, + max_results: int = None, + ) -> GetBuyersResponse: """ - Get space by ID - Retrieves details of a specific space by its ID. + Get Space ticket buyers + Retrieves a list of Users who purchased tickets to a specific Space by its ID. Args: id: The ID of the Space to be retrieved. Args: - space_fields: A comma separated list of Space fields to display. - Args: - expansions: A comma separated list of fields to expand. + pagination_token: This parameter is used to get a specified 'page' of results. Args: - user_fields: A comma separated list of User fields to display. + max_results: The maximum number of results. + Returns: + GetBuyersResponse: Response data + """ + url = self.client.base_url + "/2/spaces/{id}/buyers" + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + if pagination_token is not None: + params["pagination_token"] = pagination_token + if max_results is not None: + params["max_results"] = max_results + url = url.replace("{id}", str(id)) + headers = {} + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.get( + url, + params=params, + headers=headers, + ) + else: + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetBuyersResponse.model_validate(response_data) + + + def get_by_id( + self, + id: str, + ) -> GetByIdResponse: + """ + Get space by ID + Retrieves details of a specific space by its ID. Args: - topic_fields: A comma separated list of Topic fields to display. + id: The ID of the Space to be retrieved. Returns: - GetSpacesByIdResponse: Response data + GetByIdResponse: Response data """ url = self.client.base_url + "/2/spaces/{id}" if self.client.bearer_token: @@ -68,14 +108,6 @@ def get_spaces_by_id( if self.client.is_token_expired(): self.client.refresh_token() params = {} - if space_fields is not None: - params["space.fields"] = ",".join(str(item) for item in space_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if topic_fields is not None: - params["topic.fields"] = ",".join(str(item) for item in topic_fields) url = url.replace("{id}", str(id)) headers = {} # Make the request @@ -89,20 +121,14 @@ def get_spaces_by_id( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetSpacesByIdResponse.model_validate(response_data) + return GetByIdResponse.model_validate(response_data) - def get_spaces_posts( + def get_posts( self, id: str, max_results: int = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetSpacesPostsResponse: + ) -> GetPostsResponse: """ Get Space Posts Retrieves a list of Posts shared in a specific Space by its ID. @@ -110,20 +136,8 @@ def get_spaces_posts( id: The ID of the Space to be retrieved. Args: max_results: The number of Posts to fetch from the provided space. If not provided, the value will default to the maximum of 100. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. Returns: - GetSpacesPostsResponse: Response data + GetPostsResponse: Response data """ url = self.client.base_url + "/2/spaces/{id}/tweets" if self.client.bearer_token: @@ -142,18 +156,6 @@ def get_spaces_posts( params = {} if max_results is not None: params["max_results"] = max_results - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) url = url.replace("{id}", str(id)) headers = {} # Make the request @@ -167,34 +169,22 @@ def get_spaces_posts( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetSpacesPostsResponse.model_validate(response_data) + return GetPostsResponse.model_validate(response_data) - def get_spaces_by_creator_ids( + def get_by_ids( self, - user_ids: List, - space_fields: List = None, - expansions: List = None, - user_fields: List = None, - topic_fields: List = None, - ) -> GetSpacesByCreatorIdsResponse: + ids: List, + ) -> GetByIdsResponse: """ - Get Spaces by creator IDs - Retrieves details of Spaces created by specified User IDs. - Args: - user_ids: The IDs of Users to search through. - Args: - space_fields: A comma separated list of Space fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. + Get Spaces by IDs + Retrieves details of multiple Spaces by their IDs. Args: - topic_fields: A comma separated list of Topic fields to display. + ids: The list of Space IDs to return. Returns: - GetSpacesByCreatorIdsResponse: Response data + GetByIdsResponse: Response data """ - url = self.client.base_url + "/2/spaces/by/creator_ids" + url = self.client.base_url + "/2/spaces" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -209,16 +199,8 @@ def get_spaces_by_creator_ids( if self.client.is_token_expired(): self.client.refresh_token() params = {} - if user_ids is not None: - params["user_ids"] = ",".join(str(item) for item in user_ids) - if space_fields is not None: - params["space.fields"] = ",".join(str(item) for item in space_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if topic_fields is not None: - params["topic.fields"] = ",".join(str(item) for item in topic_fields) + if ids is not None: + params["ids"] = ",".join(str(item) for item in ids) headers = {} # Make the request response = self.client.session.get( @@ -231,101 +213,28 @@ def get_spaces_by_creator_ids( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetSpacesByCreatorIdsResponse.model_validate(response_data) + return GetByIdsResponse.model_validate(response_data) - def get_spaces_buyers( + def search( self, - id: str, - pagination_token: str = None, + query: str, + state: str = None, max_results: int = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetSpacesBuyersResponse: + ) -> SearchResponse: """ - Get Space ticket buyers - Retrieves a list of Users who purchased tickets to a specific Space by its ID. - Args: - id: The ID of the Space to be retrieved. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - max_results: The maximum number of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetSpacesBuyersResponse: Response data - """ - url = self.client.base_url + "/2/spaces/{id}/buyers" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if pagination_token is not None: - params["pagination_token"] = pagination_token - if max_results is not None: - params["max_results"] = max_results - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetSpacesBuyersResponse.model_validate(response_data) - - - def get_spaces_by_ids( - self, - ids: List, - space_fields: List = None, - expansions: List = None, - user_fields: List = None, - topic_fields: List = None, - ) -> GetSpacesByIdsResponse: - """ - Get Spaces by IDs - Retrieves details of multiple Spaces by their IDs. - Args: - ids: The list of Space IDs to return. - Args: - space_fields: A comma separated list of Space fields to display. + Search Spaces + Retrieves a list of Spaces matching the specified search query. Args: - expansions: A comma separated list of fields to expand. + query: The search query. Args: - user_fields: A comma separated list of User fields to display. + state: The state of Spaces to search for. Args: - topic_fields: A comma separated list of Topic fields to display. + max_results: The number of results to return. Returns: - GetSpacesByIdsResponse: Response data + SearchResponse: Response data """ - url = self.client.base_url + "/2/spaces" + url = self.client.base_url + "/2/spaces/search" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -340,16 +249,12 @@ def get_spaces_by_ids( if self.client.is_token_expired(): self.client.refresh_token() params = {} - if ids is not None: - params["ids"] = ",".join(str(item) for item in ids) - if space_fields is not None: - params["space.fields"] = ",".join(str(item) for item in space_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if topic_fields is not None: - params["topic.fields"] = ",".join(str(item) for item in topic_fields) + if query is not None: + params["query"] = query + if state is not None: + params["state"] = state + if max_results is not None: + params["max_results"] = max_results headers = {} # Make the request response = self.client.session.get( @@ -362,40 +267,22 @@ def get_spaces_by_ids( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetSpacesByIdsResponse.model_validate(response_data) + return SearchResponse.model_validate(response_data) - def search_spaces( + def get_by_creator_ids( self, - query: str, - state: str = None, - max_results: int = None, - space_fields: List = None, - expansions: List = None, - user_fields: List = None, - topic_fields: List = None, - ) -> SearchSpacesResponse: + user_ids: List, + ) -> GetByCreatorIdsResponse: """ - Search Spaces - Retrieves a list of Spaces matching the specified search query. - Args: - query: The search query. - Args: - state: The state of Spaces to search for. - Args: - max_results: The number of results to return. - Args: - space_fields: A comma separated list of Space fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. + Get Spaces by creator IDs + Retrieves details of Spaces created by specified User IDs. Args: - topic_fields: A comma separated list of Topic fields to display. + user_ids: The IDs of Users to search through. Returns: - SearchSpacesResponse: Response data + GetByCreatorIdsResponse: Response data """ - url = self.client.base_url + "/2/spaces/search" + url = self.client.base_url + "/2/spaces/by/creator_ids" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -410,20 +297,8 @@ def search_spaces( if self.client.is_token_expired(): self.client.refresh_token() params = {} - if query is not None: - params["query"] = query - if state is not None: - params["state"] = state - if max_results is not None: - params["max_results"] = max_results - if space_fields is not None: - params["space.fields"] = ",".join(str(item) for item in space_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if topic_fields is not None: - params["topic.fields"] = ",".join(str(item) for item in topic_fields) + if user_ids is not None: + params["user_ids"] = ",".join(str(item) for item in user_ids) headers = {} # Make the request response = self.client.session.get( @@ -436,4 +311,4 @@ def search_spaces( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return SearchSpacesResponse.model_validate(response_data) + return GetByCreatorIdsResponse.model_validate(response_data) diff --git a/xdk/python/xdk/spaces/models.py b/xdk/python/xdk/spaces/models.py index 849bdb0a..46382014 100644 --- a/xdk/python/xdk/spaces/models.py +++ b/xdk/python/xdk/spaces/models.py @@ -1,7 +1,7 @@ """ -Spaces models for the X API. +spaces models for the X API. -This module provides models for the Spaces endpoints of the X API. +This module provides models for the spaces endpoints of the X API. """ from typing import Dict, List, Optional, Any, Union, Literal @@ -9,21 +9,58 @@ from datetime import datetime -# Models for getSpacesById +# Models for get_buyers -class GetSpacesByIdResponse(BaseModel): - """Response model for getSpacesById""" +class GetBuyersResponse(BaseModel): + """Response model for get_buyers""" - data: Optional["GetSpacesByIdResponseData"] = Field(default_factory=dict) + data: Optional[List] = None + errors: Optional[List] = None + includes: Optional["GetBuyersResponseIncludes"] = None + meta: Optional["GetBuyersResponseMeta"] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetBuyersResponseIncludes(BaseModel): + """Nested model for GetBuyersResponseIncludes""" + + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetBuyersResponseMeta(BaseModel): + """Nested model for GetBuyersResponseMeta""" + + next_token: Optional[str] = None + previous_token: Optional[str] = None + result_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for get_by_id + + +class GetByIdResponse(BaseModel): + """Response model for get_by_id""" + + data: Optional["GetByIdResponseData"] = Field(default_factory=dict) errors: Optional[List] = None - includes: Optional["GetSpacesByIdResponseIncludes"] = None + includes: Optional["GetByIdResponseIncludes"] = None model_config = ConfigDict(populate_by_name=True) -class GetSpacesByIdResponseData(BaseModel): - """Nested model for GetSpacesByIdResponseData""" +class GetByIdResponseData(BaseModel): + """Nested model for GetByIdResponseData""" created_at: Optional[str] = None creator_id: Optional[str] = None @@ -46,8 +83,8 @@ class GetSpacesByIdResponseData(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetSpacesByIdResponseIncludes(BaseModel): - """Nested model for GetSpacesByIdResponseIncludes""" +class GetByIdResponseIncludes(BaseModel): + """Nested model for GetByIdResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -59,22 +96,22 @@ class GetSpacesByIdResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for getSpacesPosts +# Models for get_posts -class GetSpacesPostsResponse(BaseModel): - """Response model for getSpacesPosts""" +class GetPostsResponse(BaseModel): + """Response model for get_posts""" data: Optional[List] = None errors: Optional[List] = None - includes: Optional["GetSpacesPostsResponseIncludes"] = None - meta: Optional["GetSpacesPostsResponseMeta"] = None + includes: Optional["GetPostsResponseIncludes"] = None + meta: Optional["GetPostsResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetSpacesPostsResponseIncludes(BaseModel): - """Nested model for GetSpacesPostsResponseIncludes""" +class GetPostsResponseIncludes(BaseModel): + """Nested model for GetPostsResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -86,8 +123,8 @@ class GetSpacesPostsResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetSpacesPostsResponseMeta(BaseModel): - """Nested model for GetSpacesPostsResponseMeta""" +class GetPostsResponseMeta(BaseModel): + """Nested model for GetPostsResponseMeta""" next_token: Optional[str] = None previous_token: Optional[str] = None @@ -96,22 +133,21 @@ class GetSpacesPostsResponseMeta(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for getSpacesByCreatorIds +# Models for get_by_ids -class GetSpacesByCreatorIdsResponse(BaseModel): - """Response model for getSpacesByCreatorIds""" +class GetByIdsResponse(BaseModel): + """Response model for get_by_ids""" data: Optional[List] = None errors: Optional[List] = None - includes: Optional["GetSpacesByCreatorIdsResponseIncludes"] = None - meta: Optional["GetSpacesByCreatorIdsResponseMeta"] = None + includes: Optional["GetByIdsResponseIncludes"] = None model_config = ConfigDict(populate_by_name=True) -class GetSpacesByCreatorIdsResponseIncludes(BaseModel): - """Nested model for GetSpacesByCreatorIdsResponseIncludes""" +class GetByIdsResponseIncludes(BaseModel): + """Nested model for GetByIdsResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -123,30 +159,22 @@ class GetSpacesByCreatorIdsResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetSpacesByCreatorIdsResponseMeta(BaseModel): - """Nested model for GetSpacesByCreatorIdsResponseMeta""" - - result_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) +# Models for search -# Models for getSpacesBuyers - - -class GetSpacesBuyersResponse(BaseModel): - """Response model for getSpacesBuyers""" +class SearchResponse(BaseModel): + """Response model for search""" data: Optional[List] = None errors: Optional[List] = None - includes: Optional["GetSpacesBuyersResponseIncludes"] = None - meta: Optional["GetSpacesBuyersResponseMeta"] = None + includes: Optional["SearchResponseIncludes"] = None + meta: Optional["SearchResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetSpacesBuyersResponseIncludes(BaseModel): - """Nested model for GetSpacesBuyersResponseIncludes""" +class SearchResponseIncludes(BaseModel): + """Nested model for SearchResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -158,58 +186,30 @@ class GetSpacesBuyersResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetSpacesBuyersResponseMeta(BaseModel): - """Nested model for GetSpacesBuyersResponseMeta""" +class SearchResponseMeta(BaseModel): + """Nested model for SearchResponseMeta""" - next_token: Optional[str] = None - previous_token: Optional[str] = None result_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -# Models for getSpacesByIds - - -class GetSpacesByIdsResponse(BaseModel): - """Response model for getSpacesByIds""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetSpacesByIdsResponseIncludes"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetSpacesByIdsResponseIncludes(BaseModel): - """Nested model for GetSpacesByIdsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for searchSpaces +# Models for get_by_creator_ids -class SearchSpacesResponse(BaseModel): - """Response model for searchSpaces""" +class GetByCreatorIdsResponse(BaseModel): + """Response model for get_by_creator_ids""" data: Optional[List] = None errors: Optional[List] = None - includes: Optional["SearchSpacesResponseIncludes"] = None - meta: Optional["SearchSpacesResponseMeta"] = None + includes: Optional["GetByCreatorIdsResponseIncludes"] = None + meta: Optional["GetByCreatorIdsResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class SearchSpacesResponseIncludes(BaseModel): - """Nested model for SearchSpacesResponseIncludes""" +class GetByCreatorIdsResponseIncludes(BaseModel): + """Nested model for GetByCreatorIdsResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -221,8 +221,8 @@ class SearchSpacesResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -class SearchSpacesResponseMeta(BaseModel): - """Nested model for SearchSpacesResponseMeta""" +class GetByCreatorIdsResponseMeta(BaseModel): + """Nested model for GetByCreatorIdsResponseMeta""" result_count: Optional[int] = None diff --git a/xdk/python/xdk/stream/__init__.py b/xdk/python/xdk/stream/__init__.py index ef5dca48..2c781188 100644 --- a/xdk/python/xdk/stream/__init__.py +++ b/xdk/python/xdk/stream/__init__.py @@ -1,7 +1,7 @@ """ -Stream module for the X API. +stream module for the X API. -This module provides access to the Stream endpoints of the X API. +This module provides access to the stream endpoints of the X API. """ from .client import StreamClient diff --git a/xdk/python/xdk/stream/client.py b/xdk/python/xdk/stream/client.py index 7231fe5f..5b956a24 100644 --- a/xdk/python/xdk/stream/client.py +++ b/xdk/python/xdk/stream/client.py @@ -1,7 +1,7 @@ """ -Stream client for the X API. +stream client for the X API. -This module provides a client for interacting with the Stream endpoints of the X API. +This module provides a client for interacting with the stream endpoints of the X API. """ from __future__ import annotations @@ -12,49 +12,45 @@ if TYPE_CHECKING: from ..client import Client from .models import ( - StreamLikesFirehoseResponse, - StreamLikesComplianceResponse, - StreamPostsFirehosePtResponse, - StreamPostsComplianceResponse, - StreamPostsFirehoseJaResponse, - StreamPostsFirehoseEnResponse, - StreamPostsSampleResponse, + LikesSample10Response, + PostsSampleResponse, + GetRuleCountsResponse, + PostsFirehosePtResponse, + LabelsComplianceResponse, + LikesFirehoseResponse, + PostsResponse, + PostsFirehoseResponse, + PostsComplianceResponse, GetRulesResponse, UpdateRulesRequest, UpdateRulesResponse, - StreamUsersComplianceResponse, - StreamPostsFirehoseKoResponse, - GetRuleCountsResponse, - StreamPostsFirehoseResponse, - StreamPostsSample10Response, - StreamLikesSample10Response, - StreamLabelsComplianceResponse, - StreamPostsResponse, + LikesComplianceResponse, + UsersComplianceResponse, + PostsFirehoseEnResponse, + PostsFirehoseJaResponse, + PostsFirehoseKoResponse, + PostsSample10Response, ) class StreamClient: - """Client for Stream operations""" + """Client for stream operations""" def __init__(self, client: Client): self.client = client - def stream_likes_firehose( + def likes_sample10( self, partition: int, backfill_minutes: int = None, start_time: str = None, end_time: str = None, - like_with_tweet_author_fields: List = None, - expansions: List = None, - user_fields: List = None, - tweet_fields: List = None, - ) -> StreamLikesFirehoseResponse: + ) -> LikesSample10Response: """ - Stream all Likes - Streams all public Likes in real-time. + Stream sampled Likes + Streams a 10% sample of public Likes in real-time. Args: backfill_minutes: The number of minutes of backfill requested. Args: @@ -63,18 +59,10 @@ def stream_likes_firehose( start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Likes will be provided. Args: end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - like_with_tweet_author_fields: A comma separated list of LikeWithTweetAuthor fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Args: - tweet_fields: A comma separated list of Tweet fields to display. Returns: - StreamLikesFirehoseResponse: Response data + LikesSample10Response: Response data """ - url = self.client.base_url + "/2/likes/firehose/stream" + url = self.client.base_url + "/2/likes/sample10/stream" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -92,16 +80,6 @@ def stream_likes_firehose( params["start_time"] = start_time if end_time is not None: params["end_time"] = end_time - if like_with_tweet_author_fields is not None: - params["like_with_tweet_author.fields"] = ",".join( - str(item) for item in like_with_tweet_author_fields - ) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) headers = {} # Make the request response = self.client.session.get( @@ -114,28 +92,22 @@ def stream_likes_firehose( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return StreamLikesFirehoseResponse.model_validate(response_data) + return LikesSample10Response.model_validate(response_data) - def stream_likes_compliance( + def posts_sample( self, backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - ) -> StreamLikesComplianceResponse: + ) -> PostsSampleResponse: """ - Stream Likes compliance data - Streams all compliance data related to Likes for Users. + Stream sampled Posts + Streams a 1% sample of public Posts in real-time. Args: backfill_minutes: The number of minutes of backfill requested. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Likes Compliance events will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp from which the Likes Compliance events will be provided. Returns: - StreamLikesComplianceResponse: Response data + PostsSampleResponse: Response data """ - url = self.client.base_url + "/2/likes/compliance/stream" + url = self.client.base_url + "/2/tweets/sample/stream" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -147,10 +119,6 @@ def stream_likes_compliance( params = {} if backfill_minutes is not None: params["backfill_minutes"] = backfill_minutes - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time headers = {} # Make the request response = self.client.session.get( @@ -163,22 +131,50 @@ def stream_likes_compliance( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return StreamLikesComplianceResponse.model_validate(response_data) + return PostsSampleResponse.model_validate(response_data) - def stream_posts_firehose_pt( + def get_rule_counts( + self, + ) -> GetRuleCountsResponse: + """ + Get stream rule counts + Retrieves the count of rules in the active rule set for the filtered stream. + Returns: + GetRuleCountsResponse: Response data + """ + url = self.client.base_url + "/2/tweets/search/stream/rules/counts" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) + params = {} + headers = {} + # Make the request + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetRuleCountsResponse.model_validate(response_data) + + + def posts_firehose_pt( self, partition: int, backfill_minutes: int = None, start_time: str = None, end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreamPostsFirehosePtResponse: + ) -> PostsFirehosePtResponse: """ Stream Portuguese Posts Streams all public Portuguese-language Posts in real-time. @@ -190,20 +186,8 @@ def stream_posts_firehose_pt( start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. Args: end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. Returns: - StreamPostsFirehosePtResponse: Response data + PostsFirehosePtResponse: Response data """ url = self.client.base_url + "/2/tweets/firehose/stream/lang/pt" if self.client.bearer_token: @@ -223,18 +207,6 @@ def stream_posts_firehose_pt( params["start_time"] = start_time if end_time is not None: params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) headers = {} # Make the request response = self.client.session.get( @@ -247,31 +219,28 @@ def stream_posts_firehose_pt( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return StreamPostsFirehosePtResponse.model_validate(response_data) + return PostsFirehosePtResponse.model_validate(response_data) - def stream_posts_compliance( + def labels_compliance( self, - partition: int, backfill_minutes: int = None, start_time: str = None, end_time: str = None, - ) -> StreamPostsComplianceResponse: + ) -> LabelsComplianceResponse: """ - Stream Posts compliance data - Streams all compliance data related to Posts. + Stream Post labels + Streams all labeling events applied to Posts. Args: backfill_minutes: The number of minutes of backfill requested. Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Post Compliance events will be provided. + start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Post labels will be provided. Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Post Compliance events will be provided. + end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp from which the Post labels will be provided. Returns: - StreamPostsComplianceResponse: Response data + LabelsComplianceResponse: Response data """ - url = self.client.base_url + "/2/tweets/compliance/stream" + url = self.client.base_url + "/2/tweets/label/stream" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -283,8 +252,6 @@ def stream_posts_compliance( params = {} if backfill_minutes is not None: params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition if start_time is not None: params["start_time"] = start_time if end_time is not None: @@ -301,49 +268,82 @@ def stream_posts_compliance( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return StreamPostsComplianceResponse.model_validate(response_data) + return LabelsComplianceResponse.model_validate(response_data) - def stream_posts_firehose_ja( + def likes_firehose( self, partition: int, backfill_minutes: int = None, start_time: str = None, end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreamPostsFirehoseJaResponse: + ) -> LikesFirehoseResponse: """ - Stream Japanese Posts - Streams all public Japanese-language Posts in real-time. + Stream all Likes + Streams all public Likes in real-time. Args: backfill_minutes: The number of minutes of backfill requested. Args: partition: The partition number. Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. + start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Likes will be provided. Args: end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. + Returns: + LikesFirehoseResponse: Response data + """ + url = self.client.base_url + "/2/likes/firehose/stream" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) + params = {} + if backfill_minutes is not None: + params["backfill_minutes"] = backfill_minutes + if partition is not None: + params["partition"] = partition + if start_time is not None: + params["start_time"] = start_time + if end_time is not None: + params["end_time"] = end_time + headers = {} + # Make the request + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return LikesFirehoseResponse.model_validate(response_data) + + + def posts( + self, + backfill_minutes: int = None, + start_time: str = None, + end_time: str = None, + ) -> PostsResponse: + """ + Stream filtered Posts + Streams Posts in real-time matching the active rule set. Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. + backfill_minutes: The number of minutes of backfill requested. Args: - user_fields: A comma separated list of User fields to display. + start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Posts will be provided. Args: - place_fields: A comma separated list of Place fields to display. + end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. Returns: - StreamPostsFirehoseJaResponse: Response data + PostsResponse: Response data """ - url = self.client.base_url + "/2/tweets/firehose/stream/lang/ja" + url = self.client.base_url + "/2/tweets/search/stream" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -355,24 +355,10 @@ def stream_posts_firehose_ja( params = {} if backfill_minutes is not None: params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition if start_time is not None: params["start_time"] = start_time if end_time is not None: params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) headers = {} # Make the request response = self.client.session.get( @@ -385,25 +371,19 @@ def stream_posts_firehose_ja( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return StreamPostsFirehoseJaResponse.model_validate(response_data) + return PostsResponse.model_validate(response_data) - def stream_posts_firehose_en( + def posts_firehose( self, partition: int, backfill_minutes: int = None, start_time: str = None, end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreamPostsFirehoseEnResponse: + ) -> PostsFirehoseResponse: """ - Stream English Posts - Streams all public English-language Posts in real-time. + Stream all Posts + Streams all public Posts in real-time. Args: backfill_minutes: The number of minutes of backfill requested. Args: @@ -412,22 +392,10 @@ def stream_posts_firehose_en( start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. Args: end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. Returns: - StreamPostsFirehoseEnResponse: Response data + PostsFirehoseResponse: Response data """ - url = self.client.base_url + "/2/tweets/firehose/stream/lang/en" + url = self.client.base_url + "/2/tweets/firehose/stream" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -445,18 +413,6 @@ def stream_posts_firehose_en( params["start_time"] = start_time if end_time is not None: params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) headers = {} # Make the request response = self.client.session.get( @@ -469,40 +425,31 @@ def stream_posts_firehose_en( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return StreamPostsFirehoseEnResponse.model_validate(response_data) + return PostsFirehoseResponse.model_validate(response_data) - def stream_posts_sample( + def posts_compliance( self, + partition: int, backfill_minutes: int = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreamPostsSampleResponse: + start_time: str = None, + end_time: str = None, + ) -> PostsComplianceResponse: """ - Stream sampled Posts - Streams a 1% sample of public Posts in real-time. + Stream Posts compliance data + Streams all compliance data related to Posts. Args: backfill_minutes: The number of minutes of backfill requested. Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. + partition: The partition number. Args: - user_fields: A comma separated list of User fields to display. + start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Post Compliance events will be provided. Args: - place_fields: A comma separated list of Place fields to display. + end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Post Compliance events will be provided. Returns: - StreamPostsSampleResponse: Response data + PostsComplianceResponse: Response data """ - url = self.client.base_url + "/2/tweets/sample/stream" + url = self.client.base_url + "/2/tweets/compliance/stream" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -514,18 +461,12 @@ def stream_posts_sample( params = {} if backfill_minutes is not None: params["backfill_minutes"] = backfill_minutes - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) + if partition is not None: + params["partition"] = partition + if start_time is not None: + params["start_time"] = start_time + if end_time is not None: + params["end_time"] = end_time headers = {} # Make the request response = self.client.session.get( @@ -538,7 +479,7 @@ def stream_posts_sample( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return StreamPostsSampleResponse.model_validate(response_data) + return PostsComplianceResponse.model_validate(response_data) def get_rules( @@ -638,28 +579,25 @@ def update_rules( return UpdateRulesResponse.model_validate(response_data) - def stream_users_compliance( + def likes_compliance( self, - partition: int, backfill_minutes: int = None, start_time: str = None, end_time: str = None, - ) -> StreamUsersComplianceResponse: + ) -> LikesComplianceResponse: """ - Stream Users compliance data - Streams all compliance data related to Users. + Stream Likes compliance data + Streams all compliance data related to Likes for Users. Args: backfill_minutes: The number of minutes of backfill requested. Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the User Compliance events will be provided. + start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Likes Compliance events will be provided. Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp from which the User Compliance events will be provided. + end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp from which the Likes Compliance events will be provided. Returns: - StreamUsersComplianceResponse: Response data + LikesComplianceResponse: Response data """ - url = self.client.base_url + "/2/users/compliance/stream" + url = self.client.base_url + "/2/likes/compliance/stream" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -671,8 +609,6 @@ def stream_users_compliance( params = {} if backfill_minutes is not None: params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition if start_time is not None: params["start_time"] = start_time if end_time is not None: @@ -689,49 +625,31 @@ def stream_users_compliance( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return StreamUsersComplianceResponse.model_validate(response_data) + return LikesComplianceResponse.model_validate(response_data) - def stream_posts_firehose_ko( + def users_compliance( self, partition: int, backfill_minutes: int = None, start_time: str = None, end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreamPostsFirehoseKoResponse: + ) -> UsersComplianceResponse: """ - Stream Korean Posts - Streams all public Korean-language Posts in real-time. + Stream Users compliance data + Streams all compliance data related to Users. Args: backfill_minutes: The number of minutes of backfill requested. Args: partition: The partition number. Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. + start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the User Compliance events will be provided. Args: - place_fields: A comma separated list of Place fields to display. + end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp from which the User Compliance events will be provided. Returns: - StreamPostsFirehoseKoResponse: Response data + UsersComplianceResponse: Response data """ - url = self.client.base_url + "/2/tweets/firehose/stream/lang/ko" + url = self.client.base_url + "/2/users/compliance/stream" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -749,18 +667,6 @@ def stream_posts_firehose_ko( params["start_time"] = start_time if end_time is not None: params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) headers = {} # Make the request response = self.client.session.get( @@ -773,66 +679,19 @@ def stream_posts_firehose_ko( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return StreamPostsFirehoseKoResponse.model_validate(response_data) + return UsersComplianceResponse.model_validate(response_data) - def get_rule_counts( - self, - rules_count_fields: List = None, - ) -> GetRuleCountsResponse: - """ - Get stream rule counts - Retrieves the count of rules in the active rule set for the filtered stream. - Args: - rules_count_fields: A comma separated list of RulesCount fields to display. - Returns: - GetRuleCountsResponse: Response data - """ - url = self.client.base_url + "/2/tweets/search/stream/rules/counts" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if rules_count_fields is not None: - params["rules_count.fields"] = ",".join( - str(item) for item in rules_count_fields - ) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetRuleCountsResponse.model_validate(response_data) - - - def stream_posts_firehose( + def posts_firehose_en( self, partition: int, backfill_minutes: int = None, start_time: str = None, end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreamPostsFirehoseResponse: + ) -> PostsFirehoseEnResponse: """ - Stream all Posts - Streams all public Posts in real-time. + Stream English Posts + Streams all public English-language Posts in real-time. Args: backfill_minutes: The number of minutes of backfill requested. Args: @@ -841,22 +700,10 @@ def stream_posts_firehose( start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. Args: end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. Returns: - StreamPostsFirehoseResponse: Response data + PostsFirehoseEnResponse: Response data """ - url = self.client.base_url + "/2/tweets/firehose/stream" + url = self.client.base_url + "/2/tweets/firehose/stream/lang/en" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -874,18 +721,6 @@ def stream_posts_firehose( params["start_time"] = start_time if end_time is not None: params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) headers = {} # Make the request response = self.client.session.get( @@ -898,25 +733,19 @@ def stream_posts_firehose( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return StreamPostsFirehoseResponse.model_validate(response_data) + return PostsFirehoseEnResponse.model_validate(response_data) - def stream_posts_sample10( + def posts_firehose_ja( self, partition: int, backfill_minutes: int = None, start_time: str = None, end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreamPostsSample10Response: + ) -> PostsFirehoseJaResponse: """ - Stream 10% sampled Posts - Streams a 10% sample of public Posts in real-time. + Stream Japanese Posts + Streams all public Japanese-language Posts in real-time. Args: backfill_minutes: The number of minutes of backfill requested. Args: @@ -925,22 +754,10 @@ def stream_posts_sample10( start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. Args: end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. Returns: - StreamPostsSample10Response: Response data + PostsFirehoseJaResponse: Response data """ - url = self.client.base_url + "/2/tweets/sample10/stream" + url = self.client.base_url + "/2/tweets/firehose/stream/lang/ja" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -958,18 +775,6 @@ def stream_posts_sample10( params["start_time"] = start_time if end_time is not None: params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) headers = {} # Make the request response = self.client.session.get( @@ -982,43 +787,31 @@ def stream_posts_sample10( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return StreamPostsSample10Response.model_validate(response_data) + return PostsFirehoseJaResponse.model_validate(response_data) - def stream_likes_sample10( + def posts_firehose_ko( self, partition: int, backfill_minutes: int = None, start_time: str = None, end_time: str = None, - like_with_tweet_author_fields: List = None, - expansions: List = None, - user_fields: List = None, - tweet_fields: List = None, - ) -> StreamLikesSample10Response: + ) -> PostsFirehoseKoResponse: """ - Stream sampled Likes - Streams a 10% sample of public Likes in real-time. + Stream Korean Posts + Streams all public Korean-language Posts in real-time. Args: backfill_minutes: The number of minutes of backfill requested. Args: partition: The partition number. Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Likes will be provided. + start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. Args: end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - like_with_tweet_author_fields: A comma separated list of LikeWithTweetAuthor fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - user_fields: A comma separated list of User fields to display. - Args: - tweet_fields: A comma separated list of Tweet fields to display. Returns: - StreamLikesSample10Response: Response data + PostsFirehoseKoResponse: Response data """ - url = self.client.base_url + "/2/likes/sample10/stream" + url = self.client.base_url + "/2/tweets/firehose/stream/lang/ko" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -1036,16 +829,6 @@ def stream_likes_sample10( params["start_time"] = start_time if end_time is not None: params["end_time"] = end_time - if like_with_tweet_author_fields is not None: - params["like_with_tweet_author.fields"] = ",".join( - str(item) for item in like_with_tweet_author_fields - ) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) headers = {} # Make the request response = self.client.session.get( @@ -1058,95 +841,31 @@ def stream_likes_sample10( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return StreamLikesSample10Response.model_validate(response_data) + return PostsFirehoseKoResponse.model_validate(response_data) - def stream_labels_compliance( + def posts_sample10( self, + partition: int, backfill_minutes: int = None, start_time: str = None, end_time: str = None, - ) -> StreamLabelsComplianceResponse: + ) -> PostsSample10Response: """ - Stream Post labels - Streams all labeling events applied to Posts. + Stream 10% sampled Posts + Streams a 10% sample of public Posts in real-time. Args: backfill_minutes: The number of minutes of backfill requested. Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Post labels will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp from which the Post labels will be provided. - Returns: - StreamLabelsComplianceResponse: Response data - """ - url = self.client.base_url + "/2/tweets/label/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamLabelsComplianceResponse.model_validate(response_data) - - - def stream_posts( - self, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreamPostsResponse: - """ - Stream filtered Posts - Streams Posts in real-time matching the active rule set. - Args: - backfill_minutes: The number of minutes of backfill requested. + partition: The partition number. Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Posts will be provided. + start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. Args: end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. Returns: - StreamPostsResponse: Response data + PostsSample10Response: Response data """ - url = self.client.base_url + "/2/tweets/search/stream" + url = self.client.base_url + "/2/tweets/sample10/stream" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -1158,22 +877,12 @@ def stream_posts( params = {} if backfill_minutes is not None: params["backfill_minutes"] = backfill_minutes + if partition is not None: + params["partition"] = partition if start_time is not None: params["start_time"] = start_time if end_time is not None: params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) headers = {} # Make the request response = self.client.session.get( @@ -1186,4 +895,4 @@ def stream_posts( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return StreamPostsResponse.model_validate(response_data) + return PostsSample10Response.model_validate(response_data) diff --git a/xdk/python/xdk/stream/models.py b/xdk/python/xdk/stream/models.py index 05e46f98..96737d7f 100644 --- a/xdk/python/xdk/stream/models.py +++ b/xdk/python/xdk/stream/models.py @@ -1,7 +1,7 @@ """ -Stream models for the X API. +stream models for the X API. -This module provides models for the Stream endpoints of the X API. +This module provides models for the stream endpoints of the X API. """ from typing import Dict, List, Optional, Any, Union, Literal @@ -9,21 +9,21 @@ from datetime import datetime -# Models for streamLikesFirehose +# Models for likes_sample10 -class StreamLikesFirehoseResponse(BaseModel): - """Response model for streamLikesFirehose""" +class LikesSample10Response(BaseModel): + """Response model for likes_sample10""" - data: Optional["StreamLikesFirehoseResponseData"] = None + data: Optional["LikesSample10ResponseData"] = None errors: Optional[List] = None - includes: Optional["StreamLikesFirehoseResponseIncludes"] = None + includes: Optional["LikesSample10ResponseIncludes"] = None model_config = ConfigDict(populate_by_name=True) -class StreamLikesFirehoseResponseData(BaseModel): - """Nested model for StreamLikesFirehoseResponseData""" +class LikesSample10ResponseData(BaseModel): + """Nested model for LikesSample10ResponseData""" created_at: Optional[str] = None id: Optional[str] = None @@ -34,8 +34,8 @@ class StreamLikesFirehoseResponseData(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamLikesFirehoseResponseIncludes(BaseModel): - """Nested model for StreamLikesFirehoseResponseIncludes""" +class LikesSample10ResponseIncludes(BaseModel): + """Nested model for LikesSample10ResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -47,71 +47,55 @@ class StreamLikesFirehoseResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for streamLikesCompliance +# Models for posts_sample -class StreamLikesComplianceResponse(BaseModel): - """Response model for streamLikesCompliance""" +class PostsSampleResponse(BaseModel): + """Response model for posts_sample""" - data: Optional[Dict[str, Any]] = Field(default=None) - errors: Optional[List] = Field(default=None) - - model_config = ConfigDict(populate_by_name=True) - - -# Models for streamPostsFirehosePt - - -class StreamPostsFirehosePtResponse(BaseModel): - """Response model for streamPostsFirehosePt""" - - data: Optional["StreamPostsFirehosePtResponseData"] = None + data: Optional["PostsSampleResponseData"] = None errors: Optional[List] = None - includes: Optional["StreamPostsFirehosePtResponseIncludes"] = None + includes: Optional["PostsSampleResponseIncludes"] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehosePtResponseData(BaseModel): - """Nested model for StreamPostsFirehosePtResponseData""" +class PostsSampleResponseData(BaseModel): + """Nested model for PostsSampleResponseData""" - attachments: Optional["StreamPostsFirehosePtResponseDataAttachments"] = None + attachments: Optional["PostsSampleResponseDataAttachments"] = None author_id: Optional[str] = None community_id: Optional[str] = None context_annotations: Optional[List] = None conversation_id: Optional[str] = None created_at: Optional[str] = None display_text_range: Optional[List] = None - edit_controls: Optional["StreamPostsFirehosePtResponseDataEditControls"] = None + edit_controls: Optional["PostsSampleResponseDataEditControls"] = None edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreamPostsFirehosePtResponseDataEntities"] = None - geo: Optional["StreamPostsFirehosePtResponseDataGeo"] = None + entities: Optional["PostsSampleResponseDataEntities"] = None + geo: Optional["PostsSampleResponseDataGeo"] = None id: Optional[str] = None in_reply_to_user_id: Optional[str] = None lang: Optional[str] = None - non_public_metrics: Optional[ - "StreamPostsFirehosePtResponseDataNonPublicMetrics" - ] = None - note_tweet: Optional["StreamPostsFirehosePtResponseDataNoteTweet"] = None - organic_metrics: Optional["StreamPostsFirehosePtResponseDataOrganicMetrics"] = None + non_public_metrics: Optional["PostsSampleResponseDataNonPublicMetrics"] = None + note_tweet: Optional["PostsSampleResponseDataNoteTweet"] = None + organic_metrics: Optional["PostsSampleResponseDataOrganicMetrics"] = None possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreamPostsFirehosePtResponseDataPromotedMetrics"] = ( - None - ) - public_metrics: Optional["StreamPostsFirehosePtResponseDataPublicMetrics"] = None + promoted_metrics: Optional["PostsSampleResponseDataPromotedMetrics"] = None + public_metrics: Optional["PostsSampleResponseDataPublicMetrics"] = None referenced_tweets: Optional[List] = None reply_settings: Optional[str] = None - scopes: Optional["StreamPostsFirehosePtResponseDataScopes"] = None + scopes: Optional["PostsSampleResponseDataScopes"] = None source: Optional[str] = None text: Optional[str] = None username: Optional[str] = None - withheld: Optional["StreamPostsFirehosePtResponseDataWithheld"] = None + withheld: Optional["PostsSampleResponseDataWithheld"] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehosePtResponseDataAttachments(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataAttachments""" +class PostsSampleResponseDataAttachments(BaseModel): + """Nested model for PostsSampleResponseDataAttachments""" media_keys: Optional[List] = None media_source_tweet_id: Optional[List] = None @@ -120,8 +104,8 @@ class StreamPostsFirehosePtResponseDataAttachments(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehosePtResponseDataEditControls(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataEditControls""" +class PostsSampleResponseDataEditControls(BaseModel): + """Nested model for PostsSampleResponseDataEditControls""" editable_until: Optional[str] = None edits_remaining: Optional[int] = None @@ -130,8 +114,8 @@ class StreamPostsFirehosePtResponseDataEditControls(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehosePtResponseDataEntities(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataEntities""" +class PostsSampleResponseDataEntities(BaseModel): + """Nested model for PostsSampleResponseDataEntities""" annotations: Optional[List] = None cashtags: Optional[List] = None @@ -142,17 +126,17 @@ class StreamPostsFirehosePtResponseDataEntities(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehosePtResponseDataGeo(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataGeo""" +class PostsSampleResponseDataGeo(BaseModel): + """Nested model for PostsSampleResponseDataGeo""" - coordinates: Optional["StreamPostsFirehosePtResponseDataGeoCoordinates"] = None + coordinates: Optional["PostsSampleResponseDataGeoCoordinates"] = None place_id: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehosePtResponseDataGeoCoordinates(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataGeoCoordinates""" +class PostsSampleResponseDataGeoCoordinates(BaseModel): + """Nested model for PostsSampleResponseDataGeoCoordinates""" coordinates: Optional[List] = None type: Optional[str] = None @@ -160,25 +144,25 @@ class StreamPostsFirehosePtResponseDataGeoCoordinates(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehosePtResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataNonPublicMetrics""" +class PostsSampleResponseDataNonPublicMetrics(BaseModel): + """Nested model for PostsSampleResponseDataNonPublicMetrics""" impression_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehosePtResponseDataNoteTweet(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataNoteTweet""" +class PostsSampleResponseDataNoteTweet(BaseModel): + """Nested model for PostsSampleResponseDataNoteTweet""" - entities: Optional["StreamPostsFirehosePtResponseDataNoteTweetEntities"] = None + entities: Optional["PostsSampleResponseDataNoteTweetEntities"] = None text: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehosePtResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataNoteTweetEntities""" +class PostsSampleResponseDataNoteTweetEntities(BaseModel): + """Nested model for PostsSampleResponseDataNoteTweetEntities""" cashtags: Optional[List] = None hashtags: Optional[List] = None @@ -188,8 +172,8 @@ class StreamPostsFirehosePtResponseDataNoteTweetEntities(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehosePtResponseDataOrganicMetrics(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataOrganicMetrics""" +class PostsSampleResponseDataOrganicMetrics(BaseModel): + """Nested model for PostsSampleResponseDataOrganicMetrics""" impression_count: Optional[int] = None like_count: Optional[int] = None @@ -199,8 +183,8 @@ class StreamPostsFirehosePtResponseDataOrganicMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehosePtResponseDataPromotedMetrics(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataPromotedMetrics""" +class PostsSampleResponseDataPromotedMetrics(BaseModel): + """Nested model for PostsSampleResponseDataPromotedMetrics""" impression_count: Optional[int] = None like_count: Optional[int] = None @@ -210,8 +194,8 @@ class StreamPostsFirehosePtResponseDataPromotedMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehosePtResponseDataPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataPublicMetrics""" +class PostsSampleResponseDataPublicMetrics(BaseModel): + """Nested model for PostsSampleResponseDataPublicMetrics""" bookmark_count: Optional[int] = None impression_count: Optional[int] = None @@ -223,16 +207,16 @@ class StreamPostsFirehosePtResponseDataPublicMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehosePtResponseDataScopes(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataScopes""" +class PostsSampleResponseDataScopes(BaseModel): + """Nested model for PostsSampleResponseDataScopes""" followers: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehosePtResponseDataWithheld(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataWithheld""" +class PostsSampleResponseDataWithheld(BaseModel): + """Nested model for PostsSampleResponseDataWithheld""" copyright: Optional[bool] = None country_codes: Optional[List] = None @@ -241,8 +225,8 @@ class StreamPostsFirehosePtResponseDataWithheld(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehosePtResponseIncludes(BaseModel): - """Nested model for StreamPostsFirehosePtResponseIncludes""" +class PostsSampleResponseIncludes(BaseModel): + """Nested model for PostsSampleResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -254,71 +238,90 @@ class StreamPostsFirehosePtResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for streamPostsCompliance +# Models for get_rule_counts -class StreamPostsComplianceResponse(BaseModel): - """Response model for streamPostsCompliance""" +class GetRuleCountsResponse(BaseModel): + """Response model for get_rule_counts""" - data: Optional[Any] = Field(default=None, description="Tweet compliance data.") - errors: Optional[List] = Field(default=None) + data: Optional["GetRuleCountsResponseData"] = None + errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -# Models for streamPostsFirehoseJa +class GetRuleCountsResponseData(BaseModel): + """Nested model for GetRuleCountsResponseData""" + all_project_client_apps: Optional[List] = None + cap_per_client_app: Optional[int] = None + cap_per_project: Optional[int] = None + client_app_rules_count: Optional["GetRuleCountsResponseDataClientAppRulesCount"] = ( + None + ) + project_rules_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetRuleCountsResponseDataClientAppRulesCount(BaseModel): + """Nested model for GetRuleCountsResponseDataClientAppRulesCount""" + + client_app_id: Optional[str] = None + rule_count: Optional[int] = None -class StreamPostsFirehoseJaResponse(BaseModel): - """Response model for streamPostsFirehoseJa""" + model_config = ConfigDict(populate_by_name=True) + + +# Models for posts_firehose_pt - data: Optional["StreamPostsFirehoseJaResponseData"] = None + +class PostsFirehosePtResponse(BaseModel): + """Response model for posts_firehose_pt""" + + data: Optional["PostsFirehosePtResponseData"] = None errors: Optional[List] = None - includes: Optional["StreamPostsFirehoseJaResponseIncludes"] = None + includes: Optional["PostsFirehosePtResponseIncludes"] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseJaResponseData(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseData""" +class PostsFirehosePtResponseData(BaseModel): + """Nested model for PostsFirehosePtResponseData""" - attachments: Optional["StreamPostsFirehoseJaResponseDataAttachments"] = None + attachments: Optional["PostsFirehosePtResponseDataAttachments"] = None author_id: Optional[str] = None community_id: Optional[str] = None context_annotations: Optional[List] = None conversation_id: Optional[str] = None created_at: Optional[str] = None display_text_range: Optional[List] = None - edit_controls: Optional["StreamPostsFirehoseJaResponseDataEditControls"] = None + edit_controls: Optional["PostsFirehosePtResponseDataEditControls"] = None edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreamPostsFirehoseJaResponseDataEntities"] = None - geo: Optional["StreamPostsFirehoseJaResponseDataGeo"] = None + entities: Optional["PostsFirehosePtResponseDataEntities"] = None + geo: Optional["PostsFirehosePtResponseDataGeo"] = None id: Optional[str] = None in_reply_to_user_id: Optional[str] = None lang: Optional[str] = None - non_public_metrics: Optional[ - "StreamPostsFirehoseJaResponseDataNonPublicMetrics" - ] = None - note_tweet: Optional["StreamPostsFirehoseJaResponseDataNoteTweet"] = None - organic_metrics: Optional["StreamPostsFirehoseJaResponseDataOrganicMetrics"] = None + non_public_metrics: Optional["PostsFirehosePtResponseDataNonPublicMetrics"] = None + note_tweet: Optional["PostsFirehosePtResponseDataNoteTweet"] = None + organic_metrics: Optional["PostsFirehosePtResponseDataOrganicMetrics"] = None possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreamPostsFirehoseJaResponseDataPromotedMetrics"] = ( - None - ) - public_metrics: Optional["StreamPostsFirehoseJaResponseDataPublicMetrics"] = None + promoted_metrics: Optional["PostsFirehosePtResponseDataPromotedMetrics"] = None + public_metrics: Optional["PostsFirehosePtResponseDataPublicMetrics"] = None referenced_tweets: Optional[List] = None reply_settings: Optional[str] = None - scopes: Optional["StreamPostsFirehoseJaResponseDataScopes"] = None + scopes: Optional["PostsFirehosePtResponseDataScopes"] = None source: Optional[str] = None text: Optional[str] = None username: Optional[str] = None - withheld: Optional["StreamPostsFirehoseJaResponseDataWithheld"] = None + withheld: Optional["PostsFirehosePtResponseDataWithheld"] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseJaResponseDataAttachments(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataAttachments""" +class PostsFirehosePtResponseDataAttachments(BaseModel): + """Nested model for PostsFirehosePtResponseDataAttachments""" media_keys: Optional[List] = None media_source_tweet_id: Optional[List] = None @@ -327,8 +330,8 @@ class StreamPostsFirehoseJaResponseDataAttachments(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseJaResponseDataEditControls(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataEditControls""" +class PostsFirehosePtResponseDataEditControls(BaseModel): + """Nested model for PostsFirehosePtResponseDataEditControls""" editable_until: Optional[str] = None edits_remaining: Optional[int] = None @@ -337,8 +340,8 @@ class StreamPostsFirehoseJaResponseDataEditControls(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseJaResponseDataEntities(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataEntities""" +class PostsFirehosePtResponseDataEntities(BaseModel): + """Nested model for PostsFirehosePtResponseDataEntities""" annotations: Optional[List] = None cashtags: Optional[List] = None @@ -349,17 +352,17 @@ class StreamPostsFirehoseJaResponseDataEntities(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseJaResponseDataGeo(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataGeo""" +class PostsFirehosePtResponseDataGeo(BaseModel): + """Nested model for PostsFirehosePtResponseDataGeo""" - coordinates: Optional["StreamPostsFirehoseJaResponseDataGeoCoordinates"] = None + coordinates: Optional["PostsFirehosePtResponseDataGeoCoordinates"] = None place_id: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseJaResponseDataGeoCoordinates(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataGeoCoordinates""" +class PostsFirehosePtResponseDataGeoCoordinates(BaseModel): + """Nested model for PostsFirehosePtResponseDataGeoCoordinates""" coordinates: Optional[List] = None type: Optional[str] = None @@ -367,25 +370,25 @@ class StreamPostsFirehoseJaResponseDataGeoCoordinates(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseJaResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataNonPublicMetrics""" +class PostsFirehosePtResponseDataNonPublicMetrics(BaseModel): + """Nested model for PostsFirehosePtResponseDataNonPublicMetrics""" impression_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseJaResponseDataNoteTweet(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataNoteTweet""" +class PostsFirehosePtResponseDataNoteTweet(BaseModel): + """Nested model for PostsFirehosePtResponseDataNoteTweet""" - entities: Optional["StreamPostsFirehoseJaResponseDataNoteTweetEntities"] = None + entities: Optional["PostsFirehosePtResponseDataNoteTweetEntities"] = None text: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseJaResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataNoteTweetEntities""" +class PostsFirehosePtResponseDataNoteTweetEntities(BaseModel): + """Nested model for PostsFirehosePtResponseDataNoteTweetEntities""" cashtags: Optional[List] = None hashtags: Optional[List] = None @@ -395,8 +398,8 @@ class StreamPostsFirehoseJaResponseDataNoteTweetEntities(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseJaResponseDataOrganicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataOrganicMetrics""" +class PostsFirehosePtResponseDataOrganicMetrics(BaseModel): + """Nested model for PostsFirehosePtResponseDataOrganicMetrics""" impression_count: Optional[int] = None like_count: Optional[int] = None @@ -406,8 +409,8 @@ class StreamPostsFirehoseJaResponseDataOrganicMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseJaResponseDataPromotedMetrics(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataPromotedMetrics""" +class PostsFirehosePtResponseDataPromotedMetrics(BaseModel): + """Nested model for PostsFirehosePtResponseDataPromotedMetrics""" impression_count: Optional[int] = None like_count: Optional[int] = None @@ -417,8 +420,8 @@ class StreamPostsFirehoseJaResponseDataPromotedMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseJaResponseDataPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataPublicMetrics""" +class PostsFirehosePtResponseDataPublicMetrics(BaseModel): + """Nested model for PostsFirehosePtResponseDataPublicMetrics""" bookmark_count: Optional[int] = None impression_count: Optional[int] = None @@ -430,16 +433,16 @@ class StreamPostsFirehoseJaResponseDataPublicMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseJaResponseDataScopes(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataScopes""" +class PostsFirehosePtResponseDataScopes(BaseModel): + """Nested model for PostsFirehosePtResponseDataScopes""" followers: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseJaResponseDataWithheld(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataWithheld""" +class PostsFirehosePtResponseDataWithheld(BaseModel): + """Nested model for PostsFirehosePtResponseDataWithheld""" copyright: Optional[bool] = None country_codes: Optional[List] = None @@ -448,8 +451,8 @@ class StreamPostsFirehoseJaResponseDataWithheld(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseJaResponseIncludes(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseIncludes""" +class PostsFirehosePtResponseIncludes(BaseModel): + """Nested model for PostsFirehosePtResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -461,59 +464,106 @@ class StreamPostsFirehoseJaResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for streamPostsFirehoseEn +# Models for labels_compliance -class StreamPostsFirehoseEnResponse(BaseModel): - """Response model for streamPostsFirehoseEn""" +class LabelsComplianceResponse(BaseModel): + """Response model for labels_compliance""" - data: Optional["StreamPostsFirehoseEnResponseData"] = None + data: Optional[Any] = Field(default=None, description="Tweet label data.") + errors: Optional[List] = Field(default=None) + + model_config = ConfigDict(populate_by_name=True) + + +# Models for likes_firehose + + +class LikesFirehoseResponse(BaseModel): + """Response model for likes_firehose""" + + data: Optional["LikesFirehoseResponseData"] = None + errors: Optional[List] = None + includes: Optional["LikesFirehoseResponseIncludes"] = None + + model_config = ConfigDict(populate_by_name=True) + + +class LikesFirehoseResponseData(BaseModel): + """Nested model for LikesFirehoseResponseData""" + + created_at: Optional[str] = None + id: Optional[str] = None + liked_tweet_id: Optional[str] = None + timestamp_ms: Optional[int] = None + tweet_author_id: Optional[str] = None + + model_config = ConfigDict(populate_by_name=True) + + +class LikesFirehoseResponseIncludes(BaseModel): + """Nested model for LikesFirehoseResponseIncludes""" + + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for posts + + +class PostsResponse(BaseModel): + """Response model for posts""" + + data: Optional["PostsResponseData"] = None errors: Optional[List] = None - includes: Optional["StreamPostsFirehoseEnResponseIncludes"] = None + includes: Optional["PostsResponseIncludes"] = None + matching_rules: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseEnResponseData(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseData""" +class PostsResponseData(BaseModel): + """Nested model for PostsResponseData""" - attachments: Optional["StreamPostsFirehoseEnResponseDataAttachments"] = None + attachments: Optional["PostsResponseDataAttachments"] = None author_id: Optional[str] = None community_id: Optional[str] = None context_annotations: Optional[List] = None conversation_id: Optional[str] = None created_at: Optional[str] = None display_text_range: Optional[List] = None - edit_controls: Optional["StreamPostsFirehoseEnResponseDataEditControls"] = None + edit_controls: Optional["PostsResponseDataEditControls"] = None edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreamPostsFirehoseEnResponseDataEntities"] = None - geo: Optional["StreamPostsFirehoseEnResponseDataGeo"] = None + entities: Optional["PostsResponseDataEntities"] = None + geo: Optional["PostsResponseDataGeo"] = None id: Optional[str] = None in_reply_to_user_id: Optional[str] = None lang: Optional[str] = None - non_public_metrics: Optional[ - "StreamPostsFirehoseEnResponseDataNonPublicMetrics" - ] = None - note_tweet: Optional["StreamPostsFirehoseEnResponseDataNoteTweet"] = None - organic_metrics: Optional["StreamPostsFirehoseEnResponseDataOrganicMetrics"] = None + non_public_metrics: Optional["PostsResponseDataNonPublicMetrics"] = None + note_tweet: Optional["PostsResponseDataNoteTweet"] = None + organic_metrics: Optional["PostsResponseDataOrganicMetrics"] = None possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreamPostsFirehoseEnResponseDataPromotedMetrics"] = ( - None - ) - public_metrics: Optional["StreamPostsFirehoseEnResponseDataPublicMetrics"] = None + promoted_metrics: Optional["PostsResponseDataPromotedMetrics"] = None + public_metrics: Optional["PostsResponseDataPublicMetrics"] = None referenced_tweets: Optional[List] = None reply_settings: Optional[str] = None - scopes: Optional["StreamPostsFirehoseEnResponseDataScopes"] = None + scopes: Optional["PostsResponseDataScopes"] = None source: Optional[str] = None text: Optional[str] = None username: Optional[str] = None - withheld: Optional["StreamPostsFirehoseEnResponseDataWithheld"] = None + withheld: Optional["PostsResponseDataWithheld"] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseEnResponseDataAttachments(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataAttachments""" +class PostsResponseDataAttachments(BaseModel): + """Nested model for PostsResponseDataAttachments""" media_keys: Optional[List] = None media_source_tweet_id: Optional[List] = None @@ -522,8 +572,8 @@ class StreamPostsFirehoseEnResponseDataAttachments(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseEnResponseDataEditControls(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataEditControls""" +class PostsResponseDataEditControls(BaseModel): + """Nested model for PostsResponseDataEditControls""" editable_until: Optional[str] = None edits_remaining: Optional[int] = None @@ -532,8 +582,8 @@ class StreamPostsFirehoseEnResponseDataEditControls(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseEnResponseDataEntities(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataEntities""" +class PostsResponseDataEntities(BaseModel): + """Nested model for PostsResponseDataEntities""" annotations: Optional[List] = None cashtags: Optional[List] = None @@ -544,17 +594,17 @@ class StreamPostsFirehoseEnResponseDataEntities(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseEnResponseDataGeo(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataGeo""" +class PostsResponseDataGeo(BaseModel): + """Nested model for PostsResponseDataGeo""" - coordinates: Optional["StreamPostsFirehoseEnResponseDataGeoCoordinates"] = None + coordinates: Optional["PostsResponseDataGeoCoordinates"] = None place_id: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseEnResponseDataGeoCoordinates(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataGeoCoordinates""" +class PostsResponseDataGeoCoordinates(BaseModel): + """Nested model for PostsResponseDataGeoCoordinates""" coordinates: Optional[List] = None type: Optional[str] = None @@ -562,25 +612,25 @@ class StreamPostsFirehoseEnResponseDataGeoCoordinates(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseEnResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataNonPublicMetrics""" +class PostsResponseDataNonPublicMetrics(BaseModel): + """Nested model for PostsResponseDataNonPublicMetrics""" impression_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseEnResponseDataNoteTweet(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataNoteTweet""" +class PostsResponseDataNoteTweet(BaseModel): + """Nested model for PostsResponseDataNoteTweet""" - entities: Optional["StreamPostsFirehoseEnResponseDataNoteTweetEntities"] = None + entities: Optional["PostsResponseDataNoteTweetEntities"] = None text: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseEnResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataNoteTweetEntities""" +class PostsResponseDataNoteTweetEntities(BaseModel): + """Nested model for PostsResponseDataNoteTweetEntities""" cashtags: Optional[List] = None hashtags: Optional[List] = None @@ -590,8 +640,8 @@ class StreamPostsFirehoseEnResponseDataNoteTweetEntities(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseEnResponseDataOrganicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataOrganicMetrics""" +class PostsResponseDataOrganicMetrics(BaseModel): + """Nested model for PostsResponseDataOrganicMetrics""" impression_count: Optional[int] = None like_count: Optional[int] = None @@ -601,8 +651,8 @@ class StreamPostsFirehoseEnResponseDataOrganicMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseEnResponseDataPromotedMetrics(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataPromotedMetrics""" +class PostsResponseDataPromotedMetrics(BaseModel): + """Nested model for PostsResponseDataPromotedMetrics""" impression_count: Optional[int] = None like_count: Optional[int] = None @@ -612,8 +662,8 @@ class StreamPostsFirehoseEnResponseDataPromotedMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseEnResponseDataPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataPublicMetrics""" +class PostsResponseDataPublicMetrics(BaseModel): + """Nested model for PostsResponseDataPublicMetrics""" bookmark_count: Optional[int] = None impression_count: Optional[int] = None @@ -625,16 +675,16 @@ class StreamPostsFirehoseEnResponseDataPublicMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseEnResponseDataScopes(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataScopes""" +class PostsResponseDataScopes(BaseModel): + """Nested model for PostsResponseDataScopes""" followers: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseEnResponseDataWithheld(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataWithheld""" +class PostsResponseDataWithheld(BaseModel): + """Nested model for PostsResponseDataWithheld""" copyright: Optional[bool] = None country_codes: Optional[List] = None @@ -643,8 +693,8 @@ class StreamPostsFirehoseEnResponseDataWithheld(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseEnResponseIncludes(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseIncludes""" +class PostsResponseIncludes(BaseModel): + """Nested model for PostsResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -656,55 +706,55 @@ class StreamPostsFirehoseEnResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for streamPostsSample +# Models for posts_firehose -class StreamPostsSampleResponse(BaseModel): - """Response model for streamPostsSample""" +class PostsFirehoseResponse(BaseModel): + """Response model for posts_firehose""" - data: Optional["StreamPostsSampleResponseData"] = None + data: Optional["PostsFirehoseResponseData"] = None errors: Optional[List] = None - includes: Optional["StreamPostsSampleResponseIncludes"] = None + includes: Optional["PostsFirehoseResponseIncludes"] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsSampleResponseData(BaseModel): - """Nested model for StreamPostsSampleResponseData""" +class PostsFirehoseResponseData(BaseModel): + """Nested model for PostsFirehoseResponseData""" - attachments: Optional["StreamPostsSampleResponseDataAttachments"] = None + attachments: Optional["PostsFirehoseResponseDataAttachments"] = None author_id: Optional[str] = None community_id: Optional[str] = None context_annotations: Optional[List] = None conversation_id: Optional[str] = None created_at: Optional[str] = None display_text_range: Optional[List] = None - edit_controls: Optional["StreamPostsSampleResponseDataEditControls"] = None + edit_controls: Optional["PostsFirehoseResponseDataEditControls"] = None edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreamPostsSampleResponseDataEntities"] = None - geo: Optional["StreamPostsSampleResponseDataGeo"] = None + entities: Optional["PostsFirehoseResponseDataEntities"] = None + geo: Optional["PostsFirehoseResponseDataGeo"] = None id: Optional[str] = None in_reply_to_user_id: Optional[str] = None lang: Optional[str] = None - non_public_metrics: Optional["StreamPostsSampleResponseDataNonPublicMetrics"] = None - note_tweet: Optional["StreamPostsSampleResponseDataNoteTweet"] = None - organic_metrics: Optional["StreamPostsSampleResponseDataOrganicMetrics"] = None + non_public_metrics: Optional["PostsFirehoseResponseDataNonPublicMetrics"] = None + note_tweet: Optional["PostsFirehoseResponseDataNoteTweet"] = None + organic_metrics: Optional["PostsFirehoseResponseDataOrganicMetrics"] = None possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreamPostsSampleResponseDataPromotedMetrics"] = None - public_metrics: Optional["StreamPostsSampleResponseDataPublicMetrics"] = None + promoted_metrics: Optional["PostsFirehoseResponseDataPromotedMetrics"] = None + public_metrics: Optional["PostsFirehoseResponseDataPublicMetrics"] = None referenced_tweets: Optional[List] = None reply_settings: Optional[str] = None - scopes: Optional["StreamPostsSampleResponseDataScopes"] = None + scopes: Optional["PostsFirehoseResponseDataScopes"] = None source: Optional[str] = None text: Optional[str] = None username: Optional[str] = None - withheld: Optional["StreamPostsSampleResponseDataWithheld"] = None + withheld: Optional["PostsFirehoseResponseDataWithheld"] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsSampleResponseDataAttachments(BaseModel): - """Nested model for StreamPostsSampleResponseDataAttachments""" +class PostsFirehoseResponseDataAttachments(BaseModel): + """Nested model for PostsFirehoseResponseDataAttachments""" media_keys: Optional[List] = None media_source_tweet_id: Optional[List] = None @@ -713,8 +763,8 @@ class StreamPostsSampleResponseDataAttachments(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsSampleResponseDataEditControls(BaseModel): - """Nested model for StreamPostsSampleResponseDataEditControls""" +class PostsFirehoseResponseDataEditControls(BaseModel): + """Nested model for PostsFirehoseResponseDataEditControls""" editable_until: Optional[str] = None edits_remaining: Optional[int] = None @@ -723,8 +773,8 @@ class StreamPostsSampleResponseDataEditControls(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsSampleResponseDataEntities(BaseModel): - """Nested model for StreamPostsSampleResponseDataEntities""" +class PostsFirehoseResponseDataEntities(BaseModel): + """Nested model for PostsFirehoseResponseDataEntities""" annotations: Optional[List] = None cashtags: Optional[List] = None @@ -735,17 +785,17 @@ class StreamPostsSampleResponseDataEntities(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsSampleResponseDataGeo(BaseModel): - """Nested model for StreamPostsSampleResponseDataGeo""" +class PostsFirehoseResponseDataGeo(BaseModel): + """Nested model for PostsFirehoseResponseDataGeo""" - coordinates: Optional["StreamPostsSampleResponseDataGeoCoordinates"] = None + coordinates: Optional["PostsFirehoseResponseDataGeoCoordinates"] = None place_id: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsSampleResponseDataGeoCoordinates(BaseModel): - """Nested model for StreamPostsSampleResponseDataGeoCoordinates""" +class PostsFirehoseResponseDataGeoCoordinates(BaseModel): + """Nested model for PostsFirehoseResponseDataGeoCoordinates""" coordinates: Optional[List] = None type: Optional[str] = None @@ -753,25 +803,25 @@ class StreamPostsSampleResponseDataGeoCoordinates(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsSampleResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreamPostsSampleResponseDataNonPublicMetrics""" +class PostsFirehoseResponseDataNonPublicMetrics(BaseModel): + """Nested model for PostsFirehoseResponseDataNonPublicMetrics""" impression_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsSampleResponseDataNoteTweet(BaseModel): - """Nested model for StreamPostsSampleResponseDataNoteTweet""" +class PostsFirehoseResponseDataNoteTweet(BaseModel): + """Nested model for PostsFirehoseResponseDataNoteTweet""" - entities: Optional["StreamPostsSampleResponseDataNoteTweetEntities"] = None + entities: Optional["PostsFirehoseResponseDataNoteTweetEntities"] = None text: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsSampleResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreamPostsSampleResponseDataNoteTweetEntities""" +class PostsFirehoseResponseDataNoteTweetEntities(BaseModel): + """Nested model for PostsFirehoseResponseDataNoteTweetEntities""" cashtags: Optional[List] = None hashtags: Optional[List] = None @@ -781,8 +831,8 @@ class StreamPostsSampleResponseDataNoteTweetEntities(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsSampleResponseDataOrganicMetrics(BaseModel): - """Nested model for StreamPostsSampleResponseDataOrganicMetrics""" +class PostsFirehoseResponseDataOrganicMetrics(BaseModel): + """Nested model for PostsFirehoseResponseDataOrganicMetrics""" impression_count: Optional[int] = None like_count: Optional[int] = None @@ -792,8 +842,8 @@ class StreamPostsSampleResponseDataOrganicMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsSampleResponseDataPromotedMetrics(BaseModel): - """Nested model for StreamPostsSampleResponseDataPromotedMetrics""" +class PostsFirehoseResponseDataPromotedMetrics(BaseModel): + """Nested model for PostsFirehoseResponseDataPromotedMetrics""" impression_count: Optional[int] = None like_count: Optional[int] = None @@ -803,8 +853,8 @@ class StreamPostsSampleResponseDataPromotedMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsSampleResponseDataPublicMetrics(BaseModel): - """Nested model for StreamPostsSampleResponseDataPublicMetrics""" +class PostsFirehoseResponseDataPublicMetrics(BaseModel): + """Nested model for PostsFirehoseResponseDataPublicMetrics""" bookmark_count: Optional[int] = None impression_count: Optional[int] = None @@ -816,16 +866,16 @@ class StreamPostsSampleResponseDataPublicMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsSampleResponseDataScopes(BaseModel): - """Nested model for StreamPostsSampleResponseDataScopes""" +class PostsFirehoseResponseDataScopes(BaseModel): + """Nested model for PostsFirehoseResponseDataScopes""" followers: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsSampleResponseDataWithheld(BaseModel): - """Nested model for StreamPostsSampleResponseDataWithheld""" +class PostsFirehoseResponseDataWithheld(BaseModel): + """Nested model for PostsFirehoseResponseDataWithheld""" copyright: Optional[bool] = None country_codes: Optional[List] = None @@ -834,8 +884,8 @@ class StreamPostsSampleResponseDataWithheld(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsSampleResponseIncludes(BaseModel): - """Nested model for StreamPostsSampleResponseIncludes""" +class PostsFirehoseResponseIncludes(BaseModel): + """Nested model for PostsFirehoseResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -847,11 +897,23 @@ class StreamPostsSampleResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for getRules +# Models for posts_compliance + + +class PostsComplianceResponse(BaseModel): + """Response model for posts_compliance""" + + data: Optional[Any] = Field(default=None, description="Tweet compliance data.") + errors: Optional[List] = Field(default=None) + + model_config = ConfigDict(populate_by_name=True) + + +# Models for get_rules class GetRulesResponse(BaseModel): - """Response model for getRules""" + """Response model for get_rules""" data: Optional[List] = None meta: Optional["GetRulesResponseMeta"] = Field(default_factory=dict) @@ -870,11 +932,11 @@ class GetRulesResponseMeta(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for updateRules +# Models for update_rules class UpdateRulesRequest(BaseModel): - """Request model for updateRules""" + """Request model for update_rules""" add: Optional[List] = Field(default=None) delete: Optional[Dict[str, Any]] = Field( @@ -886,7 +948,7 @@ class UpdateRulesRequest(BaseModel): class UpdateRulesResponse(BaseModel): - """Response model for updateRules""" + """Response model for update_rules""" data: Optional[List] = None errors: Optional[List] = None @@ -906,11 +968,23 @@ class UpdateRulesResponseMeta(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for streamUsersCompliance +# Models for likes_compliance + + +class LikesComplianceResponse(BaseModel): + """Response model for likes_compliance""" + + data: Optional[Dict[str, Any]] = Field(default=None) + errors: Optional[List] = Field(default=None) + + model_config = ConfigDict(populate_by_name=True) + + +# Models for users_compliance -class StreamUsersComplianceResponse(BaseModel): - """Response model for streamUsersCompliance""" +class UsersComplianceResponse(BaseModel): + """Response model for users_compliance""" data: Optional[Any] = Field(default=None, description="User compliance data.") errors: Optional[List] = Field(default=None) @@ -918,59 +992,55 @@ class StreamUsersComplianceResponse(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for streamPostsFirehoseKo +# Models for posts_firehose_en -class StreamPostsFirehoseKoResponse(BaseModel): - """Response model for streamPostsFirehoseKo""" +class PostsFirehoseEnResponse(BaseModel): + """Response model for posts_firehose_en""" - data: Optional["StreamPostsFirehoseKoResponseData"] = None + data: Optional["PostsFirehoseEnResponseData"] = None errors: Optional[List] = None - includes: Optional["StreamPostsFirehoseKoResponseIncludes"] = None + includes: Optional["PostsFirehoseEnResponseIncludes"] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseKoResponseData(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseData""" +class PostsFirehoseEnResponseData(BaseModel): + """Nested model for PostsFirehoseEnResponseData""" - attachments: Optional["StreamPostsFirehoseKoResponseDataAttachments"] = None + attachments: Optional["PostsFirehoseEnResponseDataAttachments"] = None author_id: Optional[str] = None community_id: Optional[str] = None context_annotations: Optional[List] = None conversation_id: Optional[str] = None created_at: Optional[str] = None display_text_range: Optional[List] = None - edit_controls: Optional["StreamPostsFirehoseKoResponseDataEditControls"] = None + edit_controls: Optional["PostsFirehoseEnResponseDataEditControls"] = None edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreamPostsFirehoseKoResponseDataEntities"] = None - geo: Optional["StreamPostsFirehoseKoResponseDataGeo"] = None + entities: Optional["PostsFirehoseEnResponseDataEntities"] = None + geo: Optional["PostsFirehoseEnResponseDataGeo"] = None id: Optional[str] = None in_reply_to_user_id: Optional[str] = None lang: Optional[str] = None - non_public_metrics: Optional[ - "StreamPostsFirehoseKoResponseDataNonPublicMetrics" - ] = None - note_tweet: Optional["StreamPostsFirehoseKoResponseDataNoteTweet"] = None - organic_metrics: Optional["StreamPostsFirehoseKoResponseDataOrganicMetrics"] = None + non_public_metrics: Optional["PostsFirehoseEnResponseDataNonPublicMetrics"] = None + note_tweet: Optional["PostsFirehoseEnResponseDataNoteTweet"] = None + organic_metrics: Optional["PostsFirehoseEnResponseDataOrganicMetrics"] = None possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreamPostsFirehoseKoResponseDataPromotedMetrics"] = ( - None - ) - public_metrics: Optional["StreamPostsFirehoseKoResponseDataPublicMetrics"] = None + promoted_metrics: Optional["PostsFirehoseEnResponseDataPromotedMetrics"] = None + public_metrics: Optional["PostsFirehoseEnResponseDataPublicMetrics"] = None referenced_tweets: Optional[List] = None reply_settings: Optional[str] = None - scopes: Optional["StreamPostsFirehoseKoResponseDataScopes"] = None + scopes: Optional["PostsFirehoseEnResponseDataScopes"] = None source: Optional[str] = None text: Optional[str] = None username: Optional[str] = None - withheld: Optional["StreamPostsFirehoseKoResponseDataWithheld"] = None + withheld: Optional["PostsFirehoseEnResponseDataWithheld"] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseKoResponseDataAttachments(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataAttachments""" +class PostsFirehoseEnResponseDataAttachments(BaseModel): + """Nested model for PostsFirehoseEnResponseDataAttachments""" media_keys: Optional[List] = None media_source_tweet_id: Optional[List] = None @@ -979,8 +1049,8 @@ class StreamPostsFirehoseKoResponseDataAttachments(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseKoResponseDataEditControls(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataEditControls""" +class PostsFirehoseEnResponseDataEditControls(BaseModel): + """Nested model for PostsFirehoseEnResponseDataEditControls""" editable_until: Optional[str] = None edits_remaining: Optional[int] = None @@ -989,8 +1059,8 @@ class StreamPostsFirehoseKoResponseDataEditControls(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseKoResponseDataEntities(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataEntities""" +class PostsFirehoseEnResponseDataEntities(BaseModel): + """Nested model for PostsFirehoseEnResponseDataEntities""" annotations: Optional[List] = None cashtags: Optional[List] = None @@ -1001,17 +1071,17 @@ class StreamPostsFirehoseKoResponseDataEntities(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseKoResponseDataGeo(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataGeo""" +class PostsFirehoseEnResponseDataGeo(BaseModel): + """Nested model for PostsFirehoseEnResponseDataGeo""" - coordinates: Optional["StreamPostsFirehoseKoResponseDataGeoCoordinates"] = None + coordinates: Optional["PostsFirehoseEnResponseDataGeoCoordinates"] = None place_id: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseKoResponseDataGeoCoordinates(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataGeoCoordinates""" +class PostsFirehoseEnResponseDataGeoCoordinates(BaseModel): + """Nested model for PostsFirehoseEnResponseDataGeoCoordinates""" coordinates: Optional[List] = None type: Optional[str] = None @@ -1019,25 +1089,25 @@ class StreamPostsFirehoseKoResponseDataGeoCoordinates(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseKoResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataNonPublicMetrics""" +class PostsFirehoseEnResponseDataNonPublicMetrics(BaseModel): + """Nested model for PostsFirehoseEnResponseDataNonPublicMetrics""" impression_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseKoResponseDataNoteTweet(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataNoteTweet""" +class PostsFirehoseEnResponseDataNoteTweet(BaseModel): + """Nested model for PostsFirehoseEnResponseDataNoteTweet""" - entities: Optional["StreamPostsFirehoseKoResponseDataNoteTweetEntities"] = None + entities: Optional["PostsFirehoseEnResponseDataNoteTweetEntities"] = None text: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseKoResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataNoteTweetEntities""" +class PostsFirehoseEnResponseDataNoteTweetEntities(BaseModel): + """Nested model for PostsFirehoseEnResponseDataNoteTweetEntities""" cashtags: Optional[List] = None hashtags: Optional[List] = None @@ -1047,8 +1117,8 @@ class StreamPostsFirehoseKoResponseDataNoteTweetEntities(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseKoResponseDataOrganicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataOrganicMetrics""" +class PostsFirehoseEnResponseDataOrganicMetrics(BaseModel): + """Nested model for PostsFirehoseEnResponseDataOrganicMetrics""" impression_count: Optional[int] = None like_count: Optional[int] = None @@ -1058,8 +1128,8 @@ class StreamPostsFirehoseKoResponseDataOrganicMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseKoResponseDataPromotedMetrics(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataPromotedMetrics""" +class PostsFirehoseEnResponseDataPromotedMetrics(BaseModel): + """Nested model for PostsFirehoseEnResponseDataPromotedMetrics""" impression_count: Optional[int] = None like_count: Optional[int] = None @@ -1069,8 +1139,8 @@ class StreamPostsFirehoseKoResponseDataPromotedMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseKoResponseDataPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataPublicMetrics""" +class PostsFirehoseEnResponseDataPublicMetrics(BaseModel): + """Nested model for PostsFirehoseEnResponseDataPublicMetrics""" bookmark_count: Optional[int] = None impression_count: Optional[int] = None @@ -1082,16 +1152,16 @@ class StreamPostsFirehoseKoResponseDataPublicMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseKoResponseDataScopes(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataScopes""" +class PostsFirehoseEnResponseDataScopes(BaseModel): + """Nested model for PostsFirehoseEnResponseDataScopes""" followers: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseKoResponseDataWithheld(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataWithheld""" +class PostsFirehoseEnResponseDataWithheld(BaseModel): + """Nested model for PostsFirehoseEnResponseDataWithheld""" copyright: Optional[bool] = None country_codes: Optional[List] = None @@ -1100,8 +1170,8 @@ class StreamPostsFirehoseKoResponseDataWithheld(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseKoResponseIncludes(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseIncludes""" +class PostsFirehoseEnResponseIncludes(BaseModel): + """Nested model for PostsFirehoseEnResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -1113,92 +1183,55 @@ class StreamPostsFirehoseKoResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for getRuleCounts +# Models for posts_firehose_ja -class GetRuleCountsResponse(BaseModel): - """Response model for getRuleCounts""" +class PostsFirehoseJaResponse(BaseModel): + """Response model for posts_firehose_ja""" - data: Optional["GetRuleCountsResponseData"] = None + data: Optional["PostsFirehoseJaResponseData"] = None errors: Optional[List] = None + includes: Optional["PostsFirehoseJaResponseIncludes"] = None model_config = ConfigDict(populate_by_name=True) -class GetRuleCountsResponseData(BaseModel): - """Nested model for GetRuleCountsResponseData""" - - all_project_client_apps: Optional[List] = None - cap_per_client_app: Optional[int] = None - cap_per_project: Optional[int] = None - client_app_rules_count: Optional["GetRuleCountsResponseDataClientAppRulesCount"] = ( - None - ) - project_rules_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetRuleCountsResponseDataClientAppRulesCount(BaseModel): - """Nested model for GetRuleCountsResponseDataClientAppRulesCount""" - - client_app_id: Optional[str] = None - rule_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for streamPostsFirehose - - -class StreamPostsFirehoseResponse(BaseModel): - """Response model for streamPostsFirehose""" - - data: Optional["StreamPostsFirehoseResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreamPostsFirehoseResponseIncludes"] = None - - model_config = ConfigDict(populate_by_name=True) - +class PostsFirehoseJaResponseData(BaseModel): + """Nested model for PostsFirehoseJaResponseData""" -class StreamPostsFirehoseResponseData(BaseModel): - """Nested model for StreamPostsFirehoseResponseData""" - - attachments: Optional["StreamPostsFirehoseResponseDataAttachments"] = None + attachments: Optional["PostsFirehoseJaResponseDataAttachments"] = None author_id: Optional[str] = None community_id: Optional[str] = None context_annotations: Optional[List] = None conversation_id: Optional[str] = None created_at: Optional[str] = None display_text_range: Optional[List] = None - edit_controls: Optional["StreamPostsFirehoseResponseDataEditControls"] = None + edit_controls: Optional["PostsFirehoseJaResponseDataEditControls"] = None edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreamPostsFirehoseResponseDataEntities"] = None - geo: Optional["StreamPostsFirehoseResponseDataGeo"] = None + entities: Optional["PostsFirehoseJaResponseDataEntities"] = None + geo: Optional["PostsFirehoseJaResponseDataGeo"] = None id: Optional[str] = None in_reply_to_user_id: Optional[str] = None lang: Optional[str] = None - non_public_metrics: Optional["StreamPostsFirehoseResponseDataNonPublicMetrics"] = ( - None - ) - note_tweet: Optional["StreamPostsFirehoseResponseDataNoteTweet"] = None - organic_metrics: Optional["StreamPostsFirehoseResponseDataOrganicMetrics"] = None + non_public_metrics: Optional["PostsFirehoseJaResponseDataNonPublicMetrics"] = None + note_tweet: Optional["PostsFirehoseJaResponseDataNoteTweet"] = None + organic_metrics: Optional["PostsFirehoseJaResponseDataOrganicMetrics"] = None possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreamPostsFirehoseResponseDataPromotedMetrics"] = None - public_metrics: Optional["StreamPostsFirehoseResponseDataPublicMetrics"] = None + promoted_metrics: Optional["PostsFirehoseJaResponseDataPromotedMetrics"] = None + public_metrics: Optional["PostsFirehoseJaResponseDataPublicMetrics"] = None referenced_tweets: Optional[List] = None reply_settings: Optional[str] = None - scopes: Optional["StreamPostsFirehoseResponseDataScopes"] = None + scopes: Optional["PostsFirehoseJaResponseDataScopes"] = None source: Optional[str] = None text: Optional[str] = None username: Optional[str] = None - withheld: Optional["StreamPostsFirehoseResponseDataWithheld"] = None + withheld: Optional["PostsFirehoseJaResponseDataWithheld"] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseResponseDataAttachments(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataAttachments""" +class PostsFirehoseJaResponseDataAttachments(BaseModel): + """Nested model for PostsFirehoseJaResponseDataAttachments""" media_keys: Optional[List] = None media_source_tweet_id: Optional[List] = None @@ -1207,8 +1240,8 @@ class StreamPostsFirehoseResponseDataAttachments(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseResponseDataEditControls(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataEditControls""" +class PostsFirehoseJaResponseDataEditControls(BaseModel): + """Nested model for PostsFirehoseJaResponseDataEditControls""" editable_until: Optional[str] = None edits_remaining: Optional[int] = None @@ -1217,8 +1250,8 @@ class StreamPostsFirehoseResponseDataEditControls(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseResponseDataEntities(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataEntities""" +class PostsFirehoseJaResponseDataEntities(BaseModel): + """Nested model for PostsFirehoseJaResponseDataEntities""" annotations: Optional[List] = None cashtags: Optional[List] = None @@ -1229,17 +1262,17 @@ class StreamPostsFirehoseResponseDataEntities(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseResponseDataGeo(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataGeo""" +class PostsFirehoseJaResponseDataGeo(BaseModel): + """Nested model for PostsFirehoseJaResponseDataGeo""" - coordinates: Optional["StreamPostsFirehoseResponseDataGeoCoordinates"] = None + coordinates: Optional["PostsFirehoseJaResponseDataGeoCoordinates"] = None place_id: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseResponseDataGeoCoordinates(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataGeoCoordinates""" +class PostsFirehoseJaResponseDataGeoCoordinates(BaseModel): + """Nested model for PostsFirehoseJaResponseDataGeoCoordinates""" coordinates: Optional[List] = None type: Optional[str] = None @@ -1247,25 +1280,25 @@ class StreamPostsFirehoseResponseDataGeoCoordinates(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataNonPublicMetrics""" +class PostsFirehoseJaResponseDataNonPublicMetrics(BaseModel): + """Nested model for PostsFirehoseJaResponseDataNonPublicMetrics""" impression_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseResponseDataNoteTweet(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataNoteTweet""" +class PostsFirehoseJaResponseDataNoteTweet(BaseModel): + """Nested model for PostsFirehoseJaResponseDataNoteTweet""" - entities: Optional["StreamPostsFirehoseResponseDataNoteTweetEntities"] = None + entities: Optional["PostsFirehoseJaResponseDataNoteTweetEntities"] = None text: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataNoteTweetEntities""" +class PostsFirehoseJaResponseDataNoteTweetEntities(BaseModel): + """Nested model for PostsFirehoseJaResponseDataNoteTweetEntities""" cashtags: Optional[List] = None hashtags: Optional[List] = None @@ -1275,8 +1308,8 @@ class StreamPostsFirehoseResponseDataNoteTweetEntities(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseResponseDataOrganicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataOrganicMetrics""" +class PostsFirehoseJaResponseDataOrganicMetrics(BaseModel): + """Nested model for PostsFirehoseJaResponseDataOrganicMetrics""" impression_count: Optional[int] = None like_count: Optional[int] = None @@ -1286,8 +1319,8 @@ class StreamPostsFirehoseResponseDataOrganicMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseResponseDataPromotedMetrics(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataPromotedMetrics""" +class PostsFirehoseJaResponseDataPromotedMetrics(BaseModel): + """Nested model for PostsFirehoseJaResponseDataPromotedMetrics""" impression_count: Optional[int] = None like_count: Optional[int] = None @@ -1297,8 +1330,8 @@ class StreamPostsFirehoseResponseDataPromotedMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseResponseDataPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataPublicMetrics""" +class PostsFirehoseJaResponseDataPublicMetrics(BaseModel): + """Nested model for PostsFirehoseJaResponseDataPublicMetrics""" bookmark_count: Optional[int] = None impression_count: Optional[int] = None @@ -1310,16 +1343,16 @@ class StreamPostsFirehoseResponseDataPublicMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseResponseDataScopes(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataScopes""" +class PostsFirehoseJaResponseDataScopes(BaseModel): + """Nested model for PostsFirehoseJaResponseDataScopes""" followers: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseResponseDataWithheld(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataWithheld""" +class PostsFirehoseJaResponseDataWithheld(BaseModel): + """Nested model for PostsFirehoseJaResponseDataWithheld""" copyright: Optional[bool] = None country_codes: Optional[List] = None @@ -1328,8 +1361,8 @@ class StreamPostsFirehoseResponseDataWithheld(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsFirehoseResponseIncludes(BaseModel): - """Nested model for StreamPostsFirehoseResponseIncludes""" +class PostsFirehoseJaResponseIncludes(BaseModel): + """Nested model for PostsFirehoseJaResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -1341,57 +1374,55 @@ class StreamPostsFirehoseResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for streamPostsSample10 +# Models for posts_firehose_ko -class StreamPostsSample10Response(BaseModel): - """Response model for streamPostsSample10""" +class PostsFirehoseKoResponse(BaseModel): + """Response model for posts_firehose_ko""" - data: Optional["StreamPostsSample10ResponseData"] = None + data: Optional["PostsFirehoseKoResponseData"] = None errors: Optional[List] = None - includes: Optional["StreamPostsSample10ResponseIncludes"] = None + includes: Optional["PostsFirehoseKoResponseIncludes"] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsSample10ResponseData(BaseModel): - """Nested model for StreamPostsSample10ResponseData""" +class PostsFirehoseKoResponseData(BaseModel): + """Nested model for PostsFirehoseKoResponseData""" - attachments: Optional["StreamPostsSample10ResponseDataAttachments"] = None + attachments: Optional["PostsFirehoseKoResponseDataAttachments"] = None author_id: Optional[str] = None community_id: Optional[str] = None context_annotations: Optional[List] = None conversation_id: Optional[str] = None created_at: Optional[str] = None display_text_range: Optional[List] = None - edit_controls: Optional["StreamPostsSample10ResponseDataEditControls"] = None + edit_controls: Optional["PostsFirehoseKoResponseDataEditControls"] = None edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreamPostsSample10ResponseDataEntities"] = None - geo: Optional["StreamPostsSample10ResponseDataGeo"] = None + entities: Optional["PostsFirehoseKoResponseDataEntities"] = None + geo: Optional["PostsFirehoseKoResponseDataGeo"] = None id: Optional[str] = None in_reply_to_user_id: Optional[str] = None lang: Optional[str] = None - non_public_metrics: Optional["StreamPostsSample10ResponseDataNonPublicMetrics"] = ( - None - ) - note_tweet: Optional["StreamPostsSample10ResponseDataNoteTweet"] = None - organic_metrics: Optional["StreamPostsSample10ResponseDataOrganicMetrics"] = None + non_public_metrics: Optional["PostsFirehoseKoResponseDataNonPublicMetrics"] = None + note_tweet: Optional["PostsFirehoseKoResponseDataNoteTweet"] = None + organic_metrics: Optional["PostsFirehoseKoResponseDataOrganicMetrics"] = None possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreamPostsSample10ResponseDataPromotedMetrics"] = None - public_metrics: Optional["StreamPostsSample10ResponseDataPublicMetrics"] = None + promoted_metrics: Optional["PostsFirehoseKoResponseDataPromotedMetrics"] = None + public_metrics: Optional["PostsFirehoseKoResponseDataPublicMetrics"] = None referenced_tweets: Optional[List] = None reply_settings: Optional[str] = None - scopes: Optional["StreamPostsSample10ResponseDataScopes"] = None + scopes: Optional["PostsFirehoseKoResponseDataScopes"] = None source: Optional[str] = None text: Optional[str] = None username: Optional[str] = None - withheld: Optional["StreamPostsSample10ResponseDataWithheld"] = None + withheld: Optional["PostsFirehoseKoResponseDataWithheld"] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsSample10ResponseDataAttachments(BaseModel): - """Nested model for StreamPostsSample10ResponseDataAttachments""" +class PostsFirehoseKoResponseDataAttachments(BaseModel): + """Nested model for PostsFirehoseKoResponseDataAttachments""" media_keys: Optional[List] = None media_source_tweet_id: Optional[List] = None @@ -1400,8 +1431,8 @@ class StreamPostsSample10ResponseDataAttachments(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsSample10ResponseDataEditControls(BaseModel): - """Nested model for StreamPostsSample10ResponseDataEditControls""" +class PostsFirehoseKoResponseDataEditControls(BaseModel): + """Nested model for PostsFirehoseKoResponseDataEditControls""" editable_until: Optional[str] = None edits_remaining: Optional[int] = None @@ -1410,8 +1441,8 @@ class StreamPostsSample10ResponseDataEditControls(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsSample10ResponseDataEntities(BaseModel): - """Nested model for StreamPostsSample10ResponseDataEntities""" +class PostsFirehoseKoResponseDataEntities(BaseModel): + """Nested model for PostsFirehoseKoResponseDataEntities""" annotations: Optional[List] = None cashtags: Optional[List] = None @@ -1422,17 +1453,17 @@ class StreamPostsSample10ResponseDataEntities(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsSample10ResponseDataGeo(BaseModel): - """Nested model for StreamPostsSample10ResponseDataGeo""" +class PostsFirehoseKoResponseDataGeo(BaseModel): + """Nested model for PostsFirehoseKoResponseDataGeo""" - coordinates: Optional["StreamPostsSample10ResponseDataGeoCoordinates"] = None + coordinates: Optional["PostsFirehoseKoResponseDataGeoCoordinates"] = None place_id: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsSample10ResponseDataGeoCoordinates(BaseModel): - """Nested model for StreamPostsSample10ResponseDataGeoCoordinates""" +class PostsFirehoseKoResponseDataGeoCoordinates(BaseModel): + """Nested model for PostsFirehoseKoResponseDataGeoCoordinates""" coordinates: Optional[List] = None type: Optional[str] = None @@ -1440,25 +1471,25 @@ class StreamPostsSample10ResponseDataGeoCoordinates(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsSample10ResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreamPostsSample10ResponseDataNonPublicMetrics""" +class PostsFirehoseKoResponseDataNonPublicMetrics(BaseModel): + """Nested model for PostsFirehoseKoResponseDataNonPublicMetrics""" impression_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsSample10ResponseDataNoteTweet(BaseModel): - """Nested model for StreamPostsSample10ResponseDataNoteTweet""" +class PostsFirehoseKoResponseDataNoteTweet(BaseModel): + """Nested model for PostsFirehoseKoResponseDataNoteTweet""" - entities: Optional["StreamPostsSample10ResponseDataNoteTweetEntities"] = None + entities: Optional["PostsFirehoseKoResponseDataNoteTweetEntities"] = None text: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsSample10ResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreamPostsSample10ResponseDataNoteTweetEntities""" +class PostsFirehoseKoResponseDataNoteTweetEntities(BaseModel): + """Nested model for PostsFirehoseKoResponseDataNoteTweetEntities""" cashtags: Optional[List] = None hashtags: Optional[List] = None @@ -1468,8 +1499,8 @@ class StreamPostsSample10ResponseDataNoteTweetEntities(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsSample10ResponseDataOrganicMetrics(BaseModel): - """Nested model for StreamPostsSample10ResponseDataOrganicMetrics""" +class PostsFirehoseKoResponseDataOrganicMetrics(BaseModel): + """Nested model for PostsFirehoseKoResponseDataOrganicMetrics""" impression_count: Optional[int] = None like_count: Optional[int] = None @@ -1479,8 +1510,8 @@ class StreamPostsSample10ResponseDataOrganicMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsSample10ResponseDataPromotedMetrics(BaseModel): - """Nested model for StreamPostsSample10ResponseDataPromotedMetrics""" +class PostsFirehoseKoResponseDataPromotedMetrics(BaseModel): + """Nested model for PostsFirehoseKoResponseDataPromotedMetrics""" impression_count: Optional[int] = None like_count: Optional[int] = None @@ -1490,8 +1521,8 @@ class StreamPostsSample10ResponseDataPromotedMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsSample10ResponseDataPublicMetrics(BaseModel): - """Nested model for StreamPostsSample10ResponseDataPublicMetrics""" +class PostsFirehoseKoResponseDataPublicMetrics(BaseModel): + """Nested model for PostsFirehoseKoResponseDataPublicMetrics""" bookmark_count: Optional[int] = None impression_count: Optional[int] = None @@ -1503,16 +1534,16 @@ class StreamPostsSample10ResponseDataPublicMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsSample10ResponseDataScopes(BaseModel): - """Nested model for StreamPostsSample10ResponseDataScopes""" +class PostsFirehoseKoResponseDataScopes(BaseModel): + """Nested model for PostsFirehoseKoResponseDataScopes""" followers: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsSample10ResponseDataWithheld(BaseModel): - """Nested model for StreamPostsSample10ResponseDataWithheld""" +class PostsFirehoseKoResponseDataWithheld(BaseModel): + """Nested model for PostsFirehoseKoResponseDataWithheld""" copyright: Optional[bool] = None country_codes: Optional[List] = None @@ -1521,46 +1552,8 @@ class StreamPostsSample10ResponseDataWithheld(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsSample10ResponseIncludes(BaseModel): - """Nested model for StreamPostsSample10ResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for streamLikesSample10 - - -class StreamLikesSample10Response(BaseModel): - """Response model for streamLikesSample10""" - - data: Optional["StreamLikesSample10ResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreamLikesSample10ResponseIncludes"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamLikesSample10ResponseData(BaseModel): - """Nested model for StreamLikesSample10ResponseData""" - - created_at: Optional[str] = None - id: Optional[str] = None - liked_tweet_id: Optional[str] = None - timestamp_ms: Optional[int] = None - tweet_author_id: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamLikesSample10ResponseIncludes(BaseModel): - """Nested model for StreamLikesSample10ResponseIncludes""" +class PostsFirehoseKoResponseIncludes(BaseModel): + """Nested model for PostsFirehoseKoResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -1572,68 +1565,55 @@ class StreamLikesSample10ResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for streamLabelsCompliance - - -class StreamLabelsComplianceResponse(BaseModel): - """Response model for streamLabelsCompliance""" +# Models for posts_sample10 - data: Optional[Any] = Field(default=None, description="Tweet label data.") - errors: Optional[List] = Field(default=None) - model_config = ConfigDict(populate_by_name=True) +class PostsSample10Response(BaseModel): + """Response model for posts_sample10""" - -# Models for streamPosts - - -class StreamPostsResponse(BaseModel): - """Response model for streamPosts""" - - data: Optional["StreamPostsResponseData"] = None + data: Optional["PostsSample10ResponseData"] = None errors: Optional[List] = None - includes: Optional["StreamPostsResponseIncludes"] = None - matching_rules: Optional[List] = None + includes: Optional["PostsSample10ResponseIncludes"] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsResponseData(BaseModel): - """Nested model for StreamPostsResponseData""" +class PostsSample10ResponseData(BaseModel): + """Nested model for PostsSample10ResponseData""" - attachments: Optional["StreamPostsResponseDataAttachments"] = None + attachments: Optional["PostsSample10ResponseDataAttachments"] = None author_id: Optional[str] = None community_id: Optional[str] = None context_annotations: Optional[List] = None conversation_id: Optional[str] = None created_at: Optional[str] = None display_text_range: Optional[List] = None - edit_controls: Optional["StreamPostsResponseDataEditControls"] = None + edit_controls: Optional["PostsSample10ResponseDataEditControls"] = None edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreamPostsResponseDataEntities"] = None - geo: Optional["StreamPostsResponseDataGeo"] = None + entities: Optional["PostsSample10ResponseDataEntities"] = None + geo: Optional["PostsSample10ResponseDataGeo"] = None id: Optional[str] = None in_reply_to_user_id: Optional[str] = None lang: Optional[str] = None - non_public_metrics: Optional["StreamPostsResponseDataNonPublicMetrics"] = None - note_tweet: Optional["StreamPostsResponseDataNoteTweet"] = None - organic_metrics: Optional["StreamPostsResponseDataOrganicMetrics"] = None + non_public_metrics: Optional["PostsSample10ResponseDataNonPublicMetrics"] = None + note_tweet: Optional["PostsSample10ResponseDataNoteTweet"] = None + organic_metrics: Optional["PostsSample10ResponseDataOrganicMetrics"] = None possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreamPostsResponseDataPromotedMetrics"] = None - public_metrics: Optional["StreamPostsResponseDataPublicMetrics"] = None + promoted_metrics: Optional["PostsSample10ResponseDataPromotedMetrics"] = None + public_metrics: Optional["PostsSample10ResponseDataPublicMetrics"] = None referenced_tweets: Optional[List] = None reply_settings: Optional[str] = None - scopes: Optional["StreamPostsResponseDataScopes"] = None + scopes: Optional["PostsSample10ResponseDataScopes"] = None source: Optional[str] = None text: Optional[str] = None username: Optional[str] = None - withheld: Optional["StreamPostsResponseDataWithheld"] = None + withheld: Optional["PostsSample10ResponseDataWithheld"] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsResponseDataAttachments(BaseModel): - """Nested model for StreamPostsResponseDataAttachments""" +class PostsSample10ResponseDataAttachments(BaseModel): + """Nested model for PostsSample10ResponseDataAttachments""" media_keys: Optional[List] = None media_source_tweet_id: Optional[List] = None @@ -1642,8 +1622,8 @@ class StreamPostsResponseDataAttachments(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsResponseDataEditControls(BaseModel): - """Nested model for StreamPostsResponseDataEditControls""" +class PostsSample10ResponseDataEditControls(BaseModel): + """Nested model for PostsSample10ResponseDataEditControls""" editable_until: Optional[str] = None edits_remaining: Optional[int] = None @@ -1652,8 +1632,8 @@ class StreamPostsResponseDataEditControls(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsResponseDataEntities(BaseModel): - """Nested model for StreamPostsResponseDataEntities""" +class PostsSample10ResponseDataEntities(BaseModel): + """Nested model for PostsSample10ResponseDataEntities""" annotations: Optional[List] = None cashtags: Optional[List] = None @@ -1664,17 +1644,17 @@ class StreamPostsResponseDataEntities(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsResponseDataGeo(BaseModel): - """Nested model for StreamPostsResponseDataGeo""" +class PostsSample10ResponseDataGeo(BaseModel): + """Nested model for PostsSample10ResponseDataGeo""" - coordinates: Optional["StreamPostsResponseDataGeoCoordinates"] = None + coordinates: Optional["PostsSample10ResponseDataGeoCoordinates"] = None place_id: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsResponseDataGeoCoordinates(BaseModel): - """Nested model for StreamPostsResponseDataGeoCoordinates""" +class PostsSample10ResponseDataGeoCoordinates(BaseModel): + """Nested model for PostsSample10ResponseDataGeoCoordinates""" coordinates: Optional[List] = None type: Optional[str] = None @@ -1682,25 +1662,25 @@ class StreamPostsResponseDataGeoCoordinates(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreamPostsResponseDataNonPublicMetrics""" +class PostsSample10ResponseDataNonPublicMetrics(BaseModel): + """Nested model for PostsSample10ResponseDataNonPublicMetrics""" impression_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsResponseDataNoteTweet(BaseModel): - """Nested model for StreamPostsResponseDataNoteTweet""" +class PostsSample10ResponseDataNoteTweet(BaseModel): + """Nested model for PostsSample10ResponseDataNoteTweet""" - entities: Optional["StreamPostsResponseDataNoteTweetEntities"] = None + entities: Optional["PostsSample10ResponseDataNoteTweetEntities"] = None text: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreamPostsResponseDataNoteTweetEntities""" +class PostsSample10ResponseDataNoteTweetEntities(BaseModel): + """Nested model for PostsSample10ResponseDataNoteTweetEntities""" cashtags: Optional[List] = None hashtags: Optional[List] = None @@ -1710,8 +1690,8 @@ class StreamPostsResponseDataNoteTweetEntities(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsResponseDataOrganicMetrics(BaseModel): - """Nested model for StreamPostsResponseDataOrganicMetrics""" +class PostsSample10ResponseDataOrganicMetrics(BaseModel): + """Nested model for PostsSample10ResponseDataOrganicMetrics""" impression_count: Optional[int] = None like_count: Optional[int] = None @@ -1721,8 +1701,8 @@ class StreamPostsResponseDataOrganicMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsResponseDataPromotedMetrics(BaseModel): - """Nested model for StreamPostsResponseDataPromotedMetrics""" +class PostsSample10ResponseDataPromotedMetrics(BaseModel): + """Nested model for PostsSample10ResponseDataPromotedMetrics""" impression_count: Optional[int] = None like_count: Optional[int] = None @@ -1732,8 +1712,8 @@ class StreamPostsResponseDataPromotedMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsResponseDataPublicMetrics(BaseModel): - """Nested model for StreamPostsResponseDataPublicMetrics""" +class PostsSample10ResponseDataPublicMetrics(BaseModel): + """Nested model for PostsSample10ResponseDataPublicMetrics""" bookmark_count: Optional[int] = None impression_count: Optional[int] = None @@ -1745,16 +1725,16 @@ class StreamPostsResponseDataPublicMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsResponseDataScopes(BaseModel): - """Nested model for StreamPostsResponseDataScopes""" +class PostsSample10ResponseDataScopes(BaseModel): + """Nested model for PostsSample10ResponseDataScopes""" followers: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -class StreamPostsResponseDataWithheld(BaseModel): - """Nested model for StreamPostsResponseDataWithheld""" +class PostsSample10ResponseDataWithheld(BaseModel): + """Nested model for PostsSample10ResponseDataWithheld""" copyright: Optional[bool] = None country_codes: Optional[List] = None @@ -1763,8 +1743,8 @@ class StreamPostsResponseDataWithheld(BaseModel): model_config = ConfigDict(populate_by_name=True) -class StreamPostsResponseIncludes(BaseModel): - """Nested model for StreamPostsResponseIncludes""" +class PostsSample10ResponseIncludes(BaseModel): + """Nested model for PostsSample10ResponseIncludes""" media: Optional[List] = None places: Optional[List] = None diff --git a/xdk/python/xdk/trends/__init__.py b/xdk/python/xdk/trends/__init__.py index 0d15d2c8..97695b01 100644 --- a/xdk/python/xdk/trends/__init__.py +++ b/xdk/python/xdk/trends/__init__.py @@ -1,7 +1,7 @@ """ -Trends module for the X API. +trends module for the X API. -This module provides access to the Trends endpoints of the X API. +This module provides access to the trends endpoints of the X API. """ from .client import TrendsClient diff --git a/xdk/python/xdk/trends/client.py b/xdk/python/xdk/trends/client.py index 6ac872be..b04984a4 100644 --- a/xdk/python/xdk/trends/client.py +++ b/xdk/python/xdk/trends/client.py @@ -1,7 +1,7 @@ """ -Trends client for the X API. +trends client for the X API. -This module provides a client for interacting with the Trends endpoints of the X API. +This module provides a client for interacting with the trends endpoints of the X API. """ from __future__ import annotations @@ -12,70 +12,24 @@ if TYPE_CHECKING: from ..client import Client from .models import ( - GetUsersPersonalizedTrendsResponse, - GetTrendsByWoeidResponse, + GetByWoeidResponse, + GetPersonalizedResponse, ) class TrendsClient: - """Client for Trends operations""" + """Client for trends operations""" def __init__(self, client: Client): self.client = client - def get_users_personalized_trends( - self, - personalized_trend_fields: List = None, - ) -> GetUsersPersonalizedTrendsResponse: - """ - Get personalized Trends - Retrieves personalized trending topics for the authenticated user. - Args: - personalized_trend_fields: A comma separated list of PersonalizedTrend fields to display. - Returns: - GetUsersPersonalizedTrendsResponse: Response data - """ - url = self.client.base_url + "/2/users/personalized_trends" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if personalized_trend_fields is not None: - params["personalized_trend.fields"] = ",".join( - str(item) for item in personalized_trend_fields - ) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetUsersPersonalizedTrendsResponse.model_validate(response_data) - - - def get_trends_by_woeid( + def get_by_woeid( self, woeid: int, max_trends: int = None, - trend_fields: List = None, - ) -> GetTrendsByWoeidResponse: + ) -> GetByWoeidResponse: """ Get Trends by WOEID Retrieves trending topics for a specific location identified by its WOEID. @@ -83,10 +37,8 @@ def get_trends_by_woeid( woeid: The WOEID of the place to lookup a trend for. Args: max_trends: The maximum number of results. - Args: - trend_fields: A comma separated list of Trend fields to display. Returns: - GetTrendsByWoeidResponse: Response data + GetByWoeidResponse: Response data """ url = self.client.base_url + "/2/trends/by/woeid/{woeid}" if self.client.bearer_token: @@ -100,8 +52,6 @@ def get_trends_by_woeid( params = {} if max_trends is not None: params["max_trends"] = max_trends - if trend_fields is not None: - params["trend.fields"] = ",".join(str(item) for item in trend_fields) url = url.replace("{woeid}", str(woeid)) headers = {} # Make the request @@ -115,4 +65,42 @@ def get_trends_by_woeid( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetTrendsByWoeidResponse.model_validate(response_data) + return GetByWoeidResponse.model_validate(response_data) + + + def get_personalized( + self, + ) -> GetPersonalizedResponse: + """ + Get personalized Trends + Retrieves personalized trending topics for the authenticated user. + Returns: + GetPersonalizedResponse: Response data + """ + url = self.client.base_url + "/2/users/personalized_trends" + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + headers = {} + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.get( + url, + params=params, + headers=headers, + ) + else: + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetPersonalizedResponse.model_validate(response_data) diff --git a/xdk/python/xdk/trends/models.py b/xdk/python/xdk/trends/models.py index a50ab9a0..50cccb39 100644 --- a/xdk/python/xdk/trends/models.py +++ b/xdk/python/xdk/trends/models.py @@ -1,7 +1,7 @@ """ -Trends models for the X API. +trends models for the X API. -This module provides models for the Trends endpoints of the X API. +This module provides models for the trends endpoints of the X API. """ from typing import Dict, List, Optional, Any, Union, Literal @@ -9,11 +9,11 @@ from datetime import datetime -# Models for getUsersPersonalizedTrends +# Models for get_by_woeid -class GetUsersPersonalizedTrendsResponse(BaseModel): - """Response model for getUsersPersonalizedTrends""" +class GetByWoeidResponse(BaseModel): + """Response model for get_by_woeid""" data: Optional[List] = None errors: Optional[List] = None @@ -21,11 +21,11 @@ class GetUsersPersonalizedTrendsResponse(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for getTrendsByWoeid +# Models for get_personalized -class GetTrendsByWoeidResponse(BaseModel): - """Response model for getTrendsByWoeid""" +class GetPersonalizedResponse(BaseModel): + """Response model for get_personalized""" data: Optional[List] = None errors: Optional[List] = None diff --git a/xdk/python/xdk/tweets/__init__.py b/xdk/python/xdk/tweets/__init__.py deleted file mode 100644 index d7d8e7c7..00000000 --- a/xdk/python/xdk/tweets/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Tweets module for the X API. - -This module provides access to the Tweets endpoints of the X API. -""" - -from .client import TweetsClient - -__all__ = ["TweetsClient"] diff --git a/xdk/python/xdk/tweets/client.py b/xdk/python/xdk/tweets/client.py deleted file mode 100644 index e49e9353..00000000 --- a/xdk/python/xdk/tweets/client.py +++ /dev/null @@ -1,2702 +0,0 @@ -""" -Tweets client for the X API. - -This module provides a client for interacting with the Tweets endpoints of the X API. -""" - -from __future__ import annotations -from typing import Dict, List, Optional, Any, Union, cast, TYPE_CHECKING -import requests -import time - -if TYPE_CHECKING: - from ..client import Client -from .models import ( - UnlikePostResponse, - SearchPostsRecentResponse, - GetPostsByIdResponse, - DeletePostsResponse, - GetListsPostsResponse, - GetUsersPostsResponse, - StreamPostsFirehosePtResponse, - GetSpacesPostsResponse, - StreamPostsFirehoseJaResponse, - HidePostsReplyRequest, - HidePostsReplyResponse, - GetUsersLikedPostsResponse, - StreamPostsFirehoseEnResponse, - StreamPostsSampleResponse, - GetRulesResponse, - UpdateRulesRequest, - UpdateRulesResponse, - GetSpacesBuyersResponse, - GetPostsByIdsResponse, - CreatePostsRequest, - CreatePostsResponse, - GetUsersTimelineResponse, - GetUsersMentionsResponse, - GetInsightsHistoricalResponse, - GetPostsCountsRecentResponse, - StreamPostsFirehoseKoResponse, - GetPostsAnalyticsResponse, - GetRuleCountsResponse, - GetPostsQuotedPostsResponse, - StreamPostsFirehoseResponse, - GetInsights28HrResponse, - GetPostsRepostsResponse, - StreamPostsSample10Response, - RepostPostRequest, - RepostPostResponse, - SearchPostsAllResponse, - UnrepostPostResponse, - StreamPostsResponse, - LikePostRequest, - LikePostResponse, - GetPostsCountsAllResponse, -) - - -class TweetsClient: - """Client for Tweets operations""" - - - def __init__(self, client: Client): - self.client = client - - - def unlike_post( - self, - id: str, - tweet_id: str, - ) -> UnlikePostResponse: - """ - Unlike Post - Causes the authenticated user to Unlike a specific Post by its ID. - Args: - id: The ID of the authenticated source User that is requesting to unlike the Post. - Args: - tweet_id: The ID of the Post that the User is requesting to unlike. - Returns: - UnlikePostResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/likes/{tweet_id}" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - url = url.replace("{tweet_id}", str(tweet_id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.delete( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.delete( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return UnlikePostResponse.model_validate(response_data) - - - def search_posts_recent( - self, - query: str, - start_time: str = None, - end_time: str = None, - since_id: str = None, - until_id: str = None, - max_results: int = None, - next_token: str = None, - pagination_token: str = None, - sort_order: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> SearchPostsRecentResponse: - """ - Search recent Posts - Retrieves Posts from the last 7 days matching a search query. - Args: - query: One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The oldest UTC timestamp from which the Posts will be provided. Timestamp is in second granularity and is inclusive (i.e. 12:00:01 includes the first second of the minute). - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The newest, most recent UTC timestamp to which the Posts will be provided. Timestamp is in second granularity and is exclusive (i.e. 12:00:01 excludes the first second of the minute). - Args: - since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID. - Args: - until_id: Returns results with a Post ID less than (that is, older than) the specified ID. - Args: - max_results: The maximum number of search results to be returned by a request. - Args: - next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - pagination_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - sort_order: This order in which to return results. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - SearchPostsRecentResponse: Response data - """ - url = self.client.base_url + "/2/tweets/search/recent" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if query is not None: - params["query"] = query - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if since_id is not None: - params["since_id"] = since_id - if until_id is not None: - params["until_id"] = until_id - if max_results is not None: - params["max_results"] = max_results - if next_token is not None: - params["next_token"] = next_token - if pagination_token is not None: - params["pagination_token"] = pagination_token - if sort_order is not None: - params["sort_order"] = sort_order - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return SearchPostsRecentResponse.model_validate(response_data) - - - def get_posts_by_id( - self, - id: str, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetPostsByIdResponse: - """ - Get Post by ID - Retrieves details of a specific Post by its ID. - Args: - id: A single Post ID. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetPostsByIdResponse: Response data - """ - url = self.client.base_url + "/2/tweets/{id}" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetPostsByIdResponse.model_validate(response_data) - - - def delete_posts( - self, - id: str, - ) -> DeletePostsResponse: - """ - Delete Post - Deletes a specific Post by its ID, if owned by the authenticated user. - Args: - id: The ID of the Post to be deleted. - Returns: - DeletePostsResponse: Response data - """ - url = self.client.base_url + "/2/tweets/{id}" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.delete( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.delete( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return DeletePostsResponse.model_validate(response_data) - - - def get_lists_posts( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetListsPostsResponse: - """ - Get List Posts - Retrieves a list of Posts associated with a specific List by its ID. - Args: - id: The ID of the List. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetListsPostsResponse: Response data - """ - url = self.client.base_url + "/2/lists/{id}/tweets" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetListsPostsResponse.model_validate(response_data) - - - def get_users_posts( - self, - id: str, - since_id: str = None, - until_id: str = None, - max_results: int = None, - pagination_token: str = None, - exclude: List = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetUsersPostsResponse: - """ - Get Posts - Retrieves a list of posts authored by a specific User by their ID. - Args: - id: The ID of the User to lookup. - Args: - since_id: The minimum Post ID to be included in the result set. This parameter takes precedence over start_time if both are specified. - Args: - until_id: The maximum Post ID to be included in the result set. This parameter takes precedence over end_time if both are specified. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - exclude: The set of entities to exclude (e.g. 'replies' or 'retweets'). - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Posts will be provided. The since_id parameter takes precedence if it is also specified. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. The until_id parameter takes precedence if it is also specified. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetUsersPostsResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/tweets" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if since_id is not None: - params["since_id"] = since_id - if until_id is not None: - params["until_id"] = until_id - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if exclude is not None: - params["exclude"] = ",".join(str(item) for item in exclude) - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetUsersPostsResponse.model_validate(response_data) - - - def stream_posts_firehose_pt( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreamPostsFirehosePtResponse: - """ - Stream Portuguese Posts - Streams all public Portuguese-language Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreamPostsFirehosePtResponse: Response data - """ - url = self.client.base_url + "/2/tweets/firehose/stream/lang/pt" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamPostsFirehosePtResponse.model_validate(response_data) - - - def get_spaces_posts( - self, - id: str, - max_results: int = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetSpacesPostsResponse: - """ - Get Space Posts - Retrieves a list of Posts shared in a specific Space by its ID. - Args: - id: The ID of the Space to be retrieved. - Args: - max_results: The number of Posts to fetch from the provided space. If not provided, the value will default to the maximum of 100. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetSpacesPostsResponse: Response data - """ - url = self.client.base_url + "/2/spaces/{id}/tweets" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetSpacesPostsResponse.model_validate(response_data) - - - def stream_posts_firehose_ja( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreamPostsFirehoseJaResponse: - """ - Stream Japanese Posts - Streams all public Japanese-language Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreamPostsFirehoseJaResponse: Response data - """ - url = self.client.base_url + "/2/tweets/firehose/stream/lang/ja" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamPostsFirehoseJaResponse.model_validate(response_data) - - - def hide_posts_reply( - self, - tweet_id: str, - body: Optional[HidePostsReplyRequest] = None, - ) -> HidePostsReplyResponse: - """ - Hide reply - Hides or unhides a reply to a conversation owned by the authenticated user. - Args: - tweet_id: The ID of the reply that you want to hide or unhide. - body: Request body - Returns: - HidePostsReplyResponse: Response data - """ - url = self.client.base_url + "/2/tweets/{tweet_id}/hidden" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{tweet_id}", str(tweet_id)) - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.put( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.put( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return HidePostsReplyResponse.model_validate(response_data) - - - def get_users_liked_posts( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetUsersLikedPostsResponse: - """ - Get liked Posts - Retrieves a list of Posts liked by a specific User by their ID. - Args: - id: The ID of the User to lookup. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetUsersLikedPostsResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/liked_tweets" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetUsersLikedPostsResponse.model_validate(response_data) - - - def stream_posts_firehose_en( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreamPostsFirehoseEnResponse: - """ - Stream English Posts - Streams all public English-language Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreamPostsFirehoseEnResponse: Response data - """ - url = self.client.base_url + "/2/tweets/firehose/stream/lang/en" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamPostsFirehoseEnResponse.model_validate(response_data) - - - def stream_posts_sample( - self, - backfill_minutes: int = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreamPostsSampleResponse: - """ - Stream sampled Posts - Streams a 1% sample of public Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreamPostsSampleResponse: Response data - """ - url = self.client.base_url + "/2/tweets/sample/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamPostsSampleResponse.model_validate(response_data) - - - def get_rules( - self, - ids: List = None, - max_results: int = None, - pagination_token: str = None, - ) -> GetRulesResponse: - """ - Get stream rules - Retrieves the active rule set or a subset of rules for the filtered stream. - Args: - ids: A comma-separated list of Rule IDs. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This value is populated by passing the 'next_token' returned in a request to paginate through results. - Returns: - GetRulesResponse: Response data - """ - url = self.client.base_url + "/2/tweets/search/stream/rules" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if ids is not None: - params["ids"] = ",".join(str(item) for item in ids) - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetRulesResponse.model_validate(response_data) - - - def update_rules( - self, - body: UpdateRulesRequest, - dry_run: bool = None, - delete_all: bool = None, - ) -> UpdateRulesResponse: - """ - Update stream rules - Adds or deletes rules from the active rule set for the filtered stream. - Args: - dry_run: Dry Run can be used with both the add and delete action, with the expected result given, but without actually taking any action in the system (meaning the end state will always be as it was when the request was submitted). This is particularly useful to validate rule changes. - Args: - delete_all: Delete All can be used to delete all of the rules associated this client app, it should be specified with no other parameters. Once deleted, rules cannot be recovered. - body: Request body - Returns: - UpdateRulesResponse: Response data - """ - url = self.client.base_url + "/2/tweets/search/stream/rules" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if dry_run is not None: - params["dry_run"] = dry_run - if delete_all is not None: - params["delete_all"] = delete_all - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return UpdateRulesResponse.model_validate(response_data) - - - def get_spaces_buyers( - self, - id: str, - pagination_token: str = None, - max_results: int = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetSpacesBuyersResponse: - """ - Get Space ticket buyers - Retrieves a list of Users who purchased tickets to a specific Space by its ID. - Args: - id: The ID of the Space to be retrieved. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - max_results: The maximum number of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetSpacesBuyersResponse: Response data - """ - url = self.client.base_url + "/2/spaces/{id}/buyers" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if pagination_token is not None: - params["pagination_token"] = pagination_token - if max_results is not None: - params["max_results"] = max_results - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetSpacesBuyersResponse.model_validate(response_data) - - - def get_posts_by_ids( - self, - ids: List, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetPostsByIdsResponse: - """ - Get Posts by IDs - Retrieves details of multiple Posts by their IDs. - Args: - ids: A comma separated list of Post IDs. Up to 100 are allowed in a single request. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetPostsByIdsResponse: Response data - """ - url = self.client.base_url + "/2/tweets" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if ids is not None: - params["ids"] = ",".join(str(item) for item in ids) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetPostsByIdsResponse.model_validate(response_data) - - - def create_posts( - self, - body: CreatePostsRequest, - ) -> Dict[str, Any]: - """ - Create Post - Creates a new Post for the authenticated user. - body: Request body - Returns: - CreatePostsResponse: Response data - """ - url = self.client.base_url + "/2/tweets" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return CreatePostsResponse.model_validate(response_data) - - - def get_users_timeline( - self, - id: str, - since_id: str = None, - until_id: str = None, - max_results: int = None, - pagination_token: str = None, - exclude: List = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetUsersTimelineResponse: - """ - Get Timeline - Retrieves a reverse chronological list of Posts in the authenticated User’s Timeline. - Args: - id: The ID of the authenticated source User to list Reverse Chronological Timeline Posts of. - Args: - since_id: The minimum Post ID to be included in the result set. This parameter takes precedence over start_time if both are specified. - Args: - until_id: The maximum Post ID to be included in the result set. This parameter takes precedence over end_time if both are specified. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - exclude: The set of entities to exclude (e.g. 'replies' or 'retweets'). - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Posts will be provided. The since_id parameter takes precedence if it is also specified. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. The until_id parameter takes precedence if it is also specified. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetUsersTimelineResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/timelines/reverse_chronological" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if since_id is not None: - params["since_id"] = since_id - if until_id is not None: - params["until_id"] = until_id - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if exclude is not None: - params["exclude"] = ",".join(str(item) for item in exclude) - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetUsersTimelineResponse.model_validate(response_data) - - - def get_users_mentions( - self, - id: str, - since_id: str = None, - until_id: str = None, - max_results: int = None, - pagination_token: str = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetUsersMentionsResponse: - """ - Get mentions - Retrieves a list of Posts that mention a specific User by their ID. - Args: - id: The ID of the User to lookup. - Args: - since_id: The minimum Post ID to be included in the result set. This parameter takes precedence over start_time if both are specified. - Args: - until_id: The maximum Post ID to be included in the result set. This parameter takes precedence over end_time if both are specified. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Posts will be provided. The since_id parameter takes precedence if it is also specified. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. The until_id parameter takes precedence if it is also specified. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetUsersMentionsResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/mentions" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if since_id is not None: - params["since_id"] = since_id - if until_id is not None: - params["until_id"] = until_id - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetUsersMentionsResponse.model_validate(response_data) - - - def get_insights_historical( - self, - tweet_ids: List, - end_time: str, - start_time: str, - granularity: str, - requested_metrics: List, - engagement_fields: List = None, - ) -> GetInsightsHistoricalResponse: - """ - Get historical Post insights - Retrieves historical engagement metrics for specified Posts within a defined time range. - Args: - tweet_ids: List of PostIds for historical metrics. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range. - Args: - granularity: granularity of metrics response. - Args: - requested_metrics: request metrics for historical request. - Args: - engagement_fields: A comma separated list of Engagement fields to display. - Returns: - GetInsightsHistoricalResponse: Response data - """ - url = self.client.base_url + "/2/insights/historical" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if tweet_ids is not None: - params["tweet_ids"] = ",".join(str(item) for item in tweet_ids) - if end_time is not None: - params["end_time"] = end_time - if start_time is not None: - params["start_time"] = start_time - if granularity is not None: - params["granularity"] = granularity - if requested_metrics is not None: - params["requested_metrics"] = ",".join( - str(item) for item in requested_metrics - ) - if engagement_fields is not None: - params["engagement.fields"] = ",".join( - str(item) for item in engagement_fields - ) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetInsightsHistoricalResponse.model_validate(response_data) - - - def get_posts_counts_recent( - self, - query: str, - start_time: str = None, - end_time: str = None, - since_id: str = None, - until_id: str = None, - next_token: str = None, - pagination_token: str = None, - granularity: str = None, - search_count_fields: List = None, - ) -> GetPostsCountsRecentResponse: - """ - Get count of recent Posts - Retrieves the count of Posts from the last 7 days matching a search query. - Args: - query: One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The oldest UTC timestamp (from most recent 7 days) from which the Posts will be provided. Timestamp is in second granularity and is inclusive (i.e. 12:00:01 includes the first second of the minute). - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The newest, most recent UTC timestamp to which the Posts will be provided. Timestamp is in second granularity and is exclusive (i.e. 12:00:01 excludes the first second of the minute). - Args: - since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID. - Args: - until_id: Returns results with a Post ID less than (that is, older than) the specified ID. - Args: - next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - pagination_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - granularity: The granularity for the search counts results. - Args: - search_count_fields: A comma separated list of SearchCount fields to display. - Returns: - GetPostsCountsRecentResponse: Response data - """ - url = self.client.base_url + "/2/tweets/counts/recent" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if query is not None: - params["query"] = query - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if since_id is not None: - params["since_id"] = since_id - if until_id is not None: - params["until_id"] = until_id - if next_token is not None: - params["next_token"] = next_token - if pagination_token is not None: - params["pagination_token"] = pagination_token - if granularity is not None: - params["granularity"] = granularity - if search_count_fields is not None: - params["search_count.fields"] = ",".join( - str(item) for item in search_count_fields - ) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetPostsCountsRecentResponse.model_validate(response_data) - - - def stream_posts_firehose_ko( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreamPostsFirehoseKoResponse: - """ - Stream Korean Posts - Streams all public Korean-language Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreamPostsFirehoseKoResponse: Response data - """ - url = self.client.base_url + "/2/tweets/firehose/stream/lang/ko" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamPostsFirehoseKoResponse.model_validate(response_data) - - - def get_posts_analytics( - self, - ids: List, - end_time: str, - start_time: str, - granularity: str, - analytics_fields: List = None, - ) -> GetPostsAnalyticsResponse: - """ - Get Post analytics - Retrieves analytics data for specified Posts within a defined time range. - Args: - ids: A comma separated list of Post IDs. Up to 100 are allowed in a single request. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range. - Args: - granularity: The granularity for the search counts results. - Args: - analytics_fields: A comma separated list of Analytics fields to display. - Returns: - GetPostsAnalyticsResponse: Response data - """ - url = self.client.base_url + "/2/tweets/analytics" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if ids is not None: - params["ids"] = ",".join(str(item) for item in ids) - if end_time is not None: - params["end_time"] = end_time - if start_time is not None: - params["start_time"] = start_time - if granularity is not None: - params["granularity"] = granularity - if analytics_fields is not None: - params["analytics.fields"] = ",".join( - str(item) for item in analytics_fields - ) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetPostsAnalyticsResponse.model_validate(response_data) - - - def get_rule_counts( - self, - rules_count_fields: List = None, - ) -> GetRuleCountsResponse: - """ - Get stream rule counts - Retrieves the count of rules in the active rule set for the filtered stream. - Args: - rules_count_fields: A comma separated list of RulesCount fields to display. - Returns: - GetRuleCountsResponse: Response data - """ - url = self.client.base_url + "/2/tweets/search/stream/rules/counts" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if rules_count_fields is not None: - params["rules_count.fields"] = ",".join( - str(item) for item in rules_count_fields - ) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetRuleCountsResponse.model_validate(response_data) - - - def get_posts_quoted_posts( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - exclude: List = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetPostsQuotedPostsResponse: - """ - Get Quoted Posts - Retrieves a list of Posts that quote a specific Post by its ID. - Args: - id: A single Post ID. - Args: - max_results: The maximum number of results to be returned. - Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - exclude: The set of entities to exclude (e.g. 'replies' or 'retweets'). - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetPostsQuotedPostsResponse: Response data - """ - url = self.client.base_url + "/2/tweets/{id}/quote_tweets" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if exclude is not None: - params["exclude"] = ",".join(str(item) for item in exclude) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetPostsQuotedPostsResponse.model_validate(response_data) - - - def stream_posts_firehose( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreamPostsFirehoseResponse: - """ - Stream all Posts - Streams all public Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreamPostsFirehoseResponse: Response data - """ - url = self.client.base_url + "/2/tweets/firehose/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamPostsFirehoseResponse.model_validate(response_data) - - - def get_insights28_hr( - self, - tweet_ids: List, - granularity: str, - requested_metrics: List, - engagement_fields: List = None, - ) -> GetInsights28HrResponse: - """ - Get 28-hour Post insights - Retrieves engagement metrics for specified Posts over the last 28 hours. - Args: - tweet_ids: List of PostIds for 28hr metrics. - Args: - granularity: granularity of metrics response. - Args: - requested_metrics: request metrics for historical request. - Args: - engagement_fields: A comma separated list of Engagement fields to display. - Returns: - GetInsights28HrResponse: Response data - """ - url = self.client.base_url + "/2/insights/28hr" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if tweet_ids is not None: - params["tweet_ids"] = ",".join(str(item) for item in tweet_ids) - if granularity is not None: - params["granularity"] = granularity - if requested_metrics is not None: - params["requested_metrics"] = ",".join( - str(item) for item in requested_metrics - ) - if engagement_fields is not None: - params["engagement.fields"] = ",".join( - str(item) for item in engagement_fields - ) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetInsights28HrResponse.model_validate(response_data) - - - def get_posts_reposts( - self, - id: str, - max_results: int = None, - pagination_token: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetPostsRepostsResponse: - """ - Get Reposts - Retrieves a list of Posts that repost a specific Post by its ID. - Args: - id: A single Post ID. - Args: - max_results: The maximum number of results. - Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - GetPostsRepostsResponse: Response data - """ - url = self.client.base_url + "/2/tweets/{id}/retweets" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetPostsRepostsResponse.model_validate(response_data) - - - def stream_posts_sample10( - self, - partition: int, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreamPostsSample10Response: - """ - Stream 10% sampled Posts - Streams a 10% sample of public Posts in real-time. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - partition: The partition number. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreamPostsSample10Response: Response data - """ - url = self.client.base_url + "/2/tweets/sample10/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if partition is not None: - params["partition"] = partition - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamPostsSample10Response.model_validate(response_data) - - - def repost_post( - self, - id: str, - body: Optional[RepostPostRequest] = None, - ) -> RepostPostResponse: - """ - Repost Post - Causes the authenticated user to repost a specific Post by its ID. - Args: - id: The ID of the authenticated source User that is requesting to repost the Post. - body: Request body - Returns: - RepostPostResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/retweets" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return RepostPostResponse.model_validate(response_data) - - - def search_posts_all( - self, - query: str, - start_time: str = None, - end_time: str = None, - since_id: str = None, - until_id: str = None, - max_results: int = None, - next_token: str = None, - pagination_token: str = None, - sort_order: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> SearchPostsAllResponse: - """ - Search all Posts - Retrieves Posts from the full archive matching a search query. - Args: - query: One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The oldest UTC timestamp from which the Posts will be provided. Timestamp is in second granularity and is inclusive (i.e. 12:00:01 includes the first second of the minute). - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The newest, most recent UTC timestamp to which the Posts will be provided. Timestamp is in second granularity and is exclusive (i.e. 12:00:01 excludes the first second of the minute). - Args: - since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID. - Args: - until_id: Returns results with a Post ID less than (that is, older than) the specified ID. - Args: - max_results: The maximum number of search results to be returned by a request. - Args: - next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - pagination_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - sort_order: This order in which to return results. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - SearchPostsAllResponse: Response data - """ - url = self.client.base_url + "/2/tweets/search/all" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if query is not None: - params["query"] = query - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if since_id is not None: - params["since_id"] = since_id - if until_id is not None: - params["until_id"] = until_id - if max_results is not None: - params["max_results"] = max_results - if next_token is not None: - params["next_token"] = next_token - if pagination_token is not None: - params["pagination_token"] = pagination_token - if sort_order is not None: - params["sort_order"] = sort_order - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return SearchPostsAllResponse.model_validate(response_data) - - - def unrepost_post( - self, - id: str, - source_tweet_id: str, - ) -> UnrepostPostResponse: - """ - Unrepost Post - Causes the authenticated user to unrepost a specific Post by its ID. - Args: - id: The ID of the authenticated source User that is requesting to repost the Post. - Args: - source_tweet_id: The ID of the Post that the User is requesting to unretweet. - Returns: - UnrepostPostResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/retweets/{source_tweet_id}" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - url = url.replace("{source_tweet_id}", str(source_tweet_id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.delete( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.delete( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return UnrepostPostResponse.model_validate(response_data) - - - def stream_posts( - self, - backfill_minutes: int = None, - start_time: str = None, - end_time: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> StreamPostsResponse: - """ - Stream filtered Posts - Streams Posts in real-time matching the active rule set. - Args: - backfill_minutes: The number of minutes of backfill requested. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Posts will be provided. - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. - Returns: - StreamPostsResponse: Response data - """ - url = self.client.base_url + "/2/tweets/search/stream" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if backfill_minutes is not None: - params["backfill_minutes"] = backfill_minutes - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return StreamPostsResponse.model_validate(response_data) - - - def like_post( - self, - id: str, - body: Optional[LikePostRequest] = None, - ) -> LikePostResponse: - """ - Like Post - Causes the authenticated user to Like a specific Post by its ID. - Args: - id: The ID of the authenticated source User that is requesting to like the Post. - body: Request body - Returns: - LikePostResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/likes" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - url = url.replace("{id}", str(id)) - headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return LikePostResponse.model_validate(response_data) - - - def get_posts_counts_all( - self, - query: str, - start_time: str = None, - end_time: str = None, - since_id: str = None, - until_id: str = None, - next_token: str = None, - pagination_token: str = None, - granularity: str = None, - search_count_fields: List = None, - ) -> GetPostsCountsAllResponse: - """ - Get count of all Posts - Retrieves the count of Posts matching a search query from the full archive. - Args: - query: One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length. - Args: - start_time: YYYY-MM-DDTHH:mm:ssZ. The oldest UTC timestamp (from most recent 7 days) from which the Posts will be provided. Timestamp is in second granularity and is inclusive (i.e. 12:00:01 includes the first second of the minute). - Args: - end_time: YYYY-MM-DDTHH:mm:ssZ. The newest, most recent UTC timestamp to which the Posts will be provided. Timestamp is in second granularity and is exclusive (i.e. 12:00:01 excludes the first second of the minute). - Args: - since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID. - Args: - until_id: Returns results with a Post ID less than (that is, older than) the specified ID. - Args: - next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - pagination_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - granularity: The granularity for the search counts results. - Args: - search_count_fields: A comma separated list of SearchCount fields to display. - Returns: - GetPostsCountsAllResponse: Response data - """ - url = self.client.base_url + "/2/tweets/counts/all" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" - ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" - ) - params = {} - if query is not None: - params["query"] = query - if start_time is not None: - params["start_time"] = start_time - if end_time is not None: - params["end_time"] = end_time - if since_id is not None: - params["since_id"] = since_id - if until_id is not None: - params["until_id"] = until_id - if next_token is not None: - params["next_token"] = next_token - if pagination_token is not None: - params["pagination_token"] = pagination_token - if granularity is not None: - params["granularity"] = granularity - if search_count_fields is not None: - params["search_count.fields"] = ",".join( - str(item) for item in search_count_fields - ) - headers = {} - # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetPostsCountsAllResponse.model_validate(response_data) diff --git a/xdk/python/xdk/tweets/models.py b/xdk/python/xdk/tweets/models.py deleted file mode 100644 index 00f23985..00000000 --- a/xdk/python/xdk/tweets/models.py +++ /dev/null @@ -1,2597 +0,0 @@ -""" -Tweets models for the X API. - -This module provides models for the Tweets endpoints of the X API. -""" - -from typing import Dict, List, Optional, Any, Union, Literal -from pydantic import BaseModel, Field, ConfigDict -from datetime import datetime - - -# Models for unlikePost - - -class UnlikePostResponse(BaseModel): - """Response model for unlikePost""" - - data: Optional["UnlikePostResponseData"] = None - errors: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class UnlikePostResponseData(BaseModel): - """Nested model for UnlikePostResponseData""" - - liked: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for searchPostsRecent - - -class SearchPostsRecentResponse(BaseModel): - """Response model for searchPostsRecent""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["SearchPostsRecentResponseIncludes"] = None - meta: Optional["SearchPostsRecentResponseMeta"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class SearchPostsRecentResponseIncludes(BaseModel): - """Nested model for SearchPostsRecentResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class SearchPostsRecentResponseMeta(BaseModel): - """Nested model for SearchPostsRecentResponseMeta""" - - newest_id: Optional[str] = None - next_token: Optional[str] = None - oldest_id: Optional[str] = None - result_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getPostsById - - -class GetPostsByIdResponse(BaseModel): - """Response model for getPostsById""" - - data: Optional["GetPostsByIdResponseData"] = None - errors: Optional[List] = None - includes: Optional["GetPostsByIdResponseIncludes"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsByIdResponseData(BaseModel): - """Nested model for GetPostsByIdResponseData""" - - attachments: Optional["GetPostsByIdResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["GetPostsByIdResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["GetPostsByIdResponseDataEntities"] = None - geo: Optional["GetPostsByIdResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional["GetPostsByIdResponseDataNonPublicMetrics"] = None - note_tweet: Optional["GetPostsByIdResponseDataNoteTweet"] = None - organic_metrics: Optional["GetPostsByIdResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["GetPostsByIdResponseDataPromotedMetrics"] = None - public_metrics: Optional["GetPostsByIdResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["GetPostsByIdResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["GetPostsByIdResponseDataWithheld"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsByIdResponseDataAttachments(BaseModel): - """Nested model for GetPostsByIdResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsByIdResponseDataEditControls(BaseModel): - """Nested model for GetPostsByIdResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsByIdResponseDataEntities(BaseModel): - """Nested model for GetPostsByIdResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsByIdResponseDataGeo(BaseModel): - """Nested model for GetPostsByIdResponseDataGeo""" - - coordinates: Optional["GetPostsByIdResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsByIdResponseDataGeoCoordinates(BaseModel): - """Nested model for GetPostsByIdResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsByIdResponseDataNonPublicMetrics(BaseModel): - """Nested model for GetPostsByIdResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsByIdResponseDataNoteTweet(BaseModel): - """Nested model for GetPostsByIdResponseDataNoteTweet""" - - entities: Optional["GetPostsByIdResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsByIdResponseDataNoteTweetEntities(BaseModel): - """Nested model for GetPostsByIdResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsByIdResponseDataOrganicMetrics(BaseModel): - """Nested model for GetPostsByIdResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsByIdResponseDataPromotedMetrics(BaseModel): - """Nested model for GetPostsByIdResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsByIdResponseDataPublicMetrics(BaseModel): - """Nested model for GetPostsByIdResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsByIdResponseDataScopes(BaseModel): - """Nested model for GetPostsByIdResponseDataScopes""" - - followers: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsByIdResponseDataWithheld(BaseModel): - """Nested model for GetPostsByIdResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsByIdResponseIncludes(BaseModel): - """Nested model for GetPostsByIdResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for deletePosts - - -class DeletePostsResponse(BaseModel): - """Response model for deletePosts""" - - data: Optional["DeletePostsResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class DeletePostsResponseData(BaseModel): - """Nested model for DeletePostsResponseData""" - - deleted: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getListsPosts - - -class GetListsPostsResponse(BaseModel): - """Response model for getListsPosts""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetListsPostsResponseIncludes"] = None - meta: Optional["GetListsPostsResponseMeta"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetListsPostsResponseIncludes(BaseModel): - """Nested model for GetListsPostsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetListsPostsResponseMeta(BaseModel): - """Nested model for GetListsPostsResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getUsersPosts - - -class GetUsersPostsResponse(BaseModel): - """Response model for getUsersPosts""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetUsersPostsResponseIncludes"] = None - meta: Optional["GetUsersPostsResponseMeta"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetUsersPostsResponseIncludes(BaseModel): - """Nested model for GetUsersPostsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetUsersPostsResponseMeta(BaseModel): - """Nested model for GetUsersPostsResponseMeta""" - - newest_id: Optional[str] = None - next_token: Optional[str] = None - oldest_id: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for streamPostsFirehosePt - - -class StreamPostsFirehosePtResponse(BaseModel): - """Response model for streamPostsFirehosePt""" - - data: Optional["StreamPostsFirehosePtResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreamPostsFirehosePtResponseIncludes"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehosePtResponseData(BaseModel): - """Nested model for StreamPostsFirehosePtResponseData""" - - attachments: Optional["StreamPostsFirehosePtResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreamPostsFirehosePtResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreamPostsFirehosePtResponseDataEntities"] = None - geo: Optional["StreamPostsFirehosePtResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional[ - "StreamPostsFirehosePtResponseDataNonPublicMetrics" - ] = None - note_tweet: Optional["StreamPostsFirehosePtResponseDataNoteTweet"] = None - organic_metrics: Optional["StreamPostsFirehosePtResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreamPostsFirehosePtResponseDataPromotedMetrics"] = ( - None - ) - public_metrics: Optional["StreamPostsFirehosePtResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreamPostsFirehosePtResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreamPostsFirehosePtResponseDataWithheld"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehosePtResponseDataAttachments(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehosePtResponseDataEditControls(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehosePtResponseDataEntities(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehosePtResponseDataGeo(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataGeo""" - - coordinates: Optional["StreamPostsFirehosePtResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehosePtResponseDataGeoCoordinates(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehosePtResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehosePtResponseDataNoteTweet(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataNoteTweet""" - - entities: Optional["StreamPostsFirehosePtResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehosePtResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehosePtResponseDataOrganicMetrics(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehosePtResponseDataPromotedMetrics(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehosePtResponseDataPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehosePtResponseDataScopes(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataScopes""" - - followers: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehosePtResponseDataWithheld(BaseModel): - """Nested model for StreamPostsFirehosePtResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehosePtResponseIncludes(BaseModel): - """Nested model for StreamPostsFirehosePtResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getSpacesPosts - - -class GetSpacesPostsResponse(BaseModel): - """Response model for getSpacesPosts""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetSpacesPostsResponseIncludes"] = None - meta: Optional["GetSpacesPostsResponseMeta"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetSpacesPostsResponseIncludes(BaseModel): - """Nested model for GetSpacesPostsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetSpacesPostsResponseMeta(BaseModel): - """Nested model for GetSpacesPostsResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for streamPostsFirehoseJa - - -class StreamPostsFirehoseJaResponse(BaseModel): - """Response model for streamPostsFirehoseJa""" - - data: Optional["StreamPostsFirehoseJaResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreamPostsFirehoseJaResponseIncludes"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseJaResponseData(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseData""" - - attachments: Optional["StreamPostsFirehoseJaResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreamPostsFirehoseJaResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreamPostsFirehoseJaResponseDataEntities"] = None - geo: Optional["StreamPostsFirehoseJaResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional[ - "StreamPostsFirehoseJaResponseDataNonPublicMetrics" - ] = None - note_tweet: Optional["StreamPostsFirehoseJaResponseDataNoteTweet"] = None - organic_metrics: Optional["StreamPostsFirehoseJaResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreamPostsFirehoseJaResponseDataPromotedMetrics"] = ( - None - ) - public_metrics: Optional["StreamPostsFirehoseJaResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreamPostsFirehoseJaResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreamPostsFirehoseJaResponseDataWithheld"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseJaResponseDataAttachments(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseJaResponseDataEditControls(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseJaResponseDataEntities(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseJaResponseDataGeo(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataGeo""" - - coordinates: Optional["StreamPostsFirehoseJaResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseJaResponseDataGeoCoordinates(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseJaResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseJaResponseDataNoteTweet(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataNoteTweet""" - - entities: Optional["StreamPostsFirehoseJaResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseJaResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseJaResponseDataOrganicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseJaResponseDataPromotedMetrics(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseJaResponseDataPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseJaResponseDataScopes(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataScopes""" - - followers: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseJaResponseDataWithheld(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseJaResponseIncludes(BaseModel): - """Nested model for StreamPostsFirehoseJaResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for hidePostsReply - - -class HidePostsReplyRequest(BaseModel): - """Request model for hidePostsReply""" - - hidden: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class HidePostsReplyResponse(BaseModel): - """Response model for hidePostsReply""" - - data: Optional["HidePostsReplyResponseData"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class HidePostsReplyResponseData(BaseModel): - """Nested model for HidePostsReplyResponseData""" - - hidden: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getUsersLikedPosts - - -class GetUsersLikedPostsResponse(BaseModel): - """Response model for getUsersLikedPosts""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetUsersLikedPostsResponseIncludes"] = None - meta: Optional["GetUsersLikedPostsResponseMeta"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetUsersLikedPostsResponseIncludes(BaseModel): - """Nested model for GetUsersLikedPostsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetUsersLikedPostsResponseMeta(BaseModel): - """Nested model for GetUsersLikedPostsResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for streamPostsFirehoseEn - - -class StreamPostsFirehoseEnResponse(BaseModel): - """Response model for streamPostsFirehoseEn""" - - data: Optional["StreamPostsFirehoseEnResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreamPostsFirehoseEnResponseIncludes"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseEnResponseData(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseData""" - - attachments: Optional["StreamPostsFirehoseEnResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreamPostsFirehoseEnResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreamPostsFirehoseEnResponseDataEntities"] = None - geo: Optional["StreamPostsFirehoseEnResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional[ - "StreamPostsFirehoseEnResponseDataNonPublicMetrics" - ] = None - note_tweet: Optional["StreamPostsFirehoseEnResponseDataNoteTweet"] = None - organic_metrics: Optional["StreamPostsFirehoseEnResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreamPostsFirehoseEnResponseDataPromotedMetrics"] = ( - None - ) - public_metrics: Optional["StreamPostsFirehoseEnResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreamPostsFirehoseEnResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreamPostsFirehoseEnResponseDataWithheld"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseEnResponseDataAttachments(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseEnResponseDataEditControls(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseEnResponseDataEntities(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseEnResponseDataGeo(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataGeo""" - - coordinates: Optional["StreamPostsFirehoseEnResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseEnResponseDataGeoCoordinates(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseEnResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseEnResponseDataNoteTweet(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataNoteTweet""" - - entities: Optional["StreamPostsFirehoseEnResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseEnResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseEnResponseDataOrganicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseEnResponseDataPromotedMetrics(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseEnResponseDataPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseEnResponseDataScopes(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataScopes""" - - followers: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseEnResponseDataWithheld(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseEnResponseIncludes(BaseModel): - """Nested model for StreamPostsFirehoseEnResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for streamPostsSample - - -class StreamPostsSampleResponse(BaseModel): - """Response model for streamPostsSample""" - - data: Optional["StreamPostsSampleResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreamPostsSampleResponseIncludes"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSampleResponseData(BaseModel): - """Nested model for StreamPostsSampleResponseData""" - - attachments: Optional["StreamPostsSampleResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreamPostsSampleResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreamPostsSampleResponseDataEntities"] = None - geo: Optional["StreamPostsSampleResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional["StreamPostsSampleResponseDataNonPublicMetrics"] = None - note_tweet: Optional["StreamPostsSampleResponseDataNoteTweet"] = None - organic_metrics: Optional["StreamPostsSampleResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreamPostsSampleResponseDataPromotedMetrics"] = None - public_metrics: Optional["StreamPostsSampleResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreamPostsSampleResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreamPostsSampleResponseDataWithheld"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSampleResponseDataAttachments(BaseModel): - """Nested model for StreamPostsSampleResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSampleResponseDataEditControls(BaseModel): - """Nested model for StreamPostsSampleResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSampleResponseDataEntities(BaseModel): - """Nested model for StreamPostsSampleResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSampleResponseDataGeo(BaseModel): - """Nested model for StreamPostsSampleResponseDataGeo""" - - coordinates: Optional["StreamPostsSampleResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSampleResponseDataGeoCoordinates(BaseModel): - """Nested model for StreamPostsSampleResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSampleResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreamPostsSampleResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSampleResponseDataNoteTweet(BaseModel): - """Nested model for StreamPostsSampleResponseDataNoteTweet""" - - entities: Optional["StreamPostsSampleResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSampleResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreamPostsSampleResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSampleResponseDataOrganicMetrics(BaseModel): - """Nested model for StreamPostsSampleResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSampleResponseDataPromotedMetrics(BaseModel): - """Nested model for StreamPostsSampleResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSampleResponseDataPublicMetrics(BaseModel): - """Nested model for StreamPostsSampleResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSampleResponseDataScopes(BaseModel): - """Nested model for StreamPostsSampleResponseDataScopes""" - - followers: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSampleResponseDataWithheld(BaseModel): - """Nested model for StreamPostsSampleResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSampleResponseIncludes(BaseModel): - """Nested model for StreamPostsSampleResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getRules - - -class GetRulesResponse(BaseModel): - """Response model for getRules""" - - data: Optional[List] = None - meta: Optional["GetRulesResponseMeta"] = Field(default_factory=dict) - - model_config = ConfigDict(populate_by_name=True) - - -class GetRulesResponseMeta(BaseModel): - """Nested model for GetRulesResponseMeta""" - - next_token: Optional[str] = None - result_count: Optional[int] = None - sent: Optional[str] = None - summary: Any = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for updateRules - - -class UpdateRulesRequest(BaseModel): - """Request model for updateRules""" - - add: Optional[List] = Field(default=None) - delete: Optional[Dict[str, Any]] = Field( - default=None, - description="IDs and values of all deleted user-specified stream filtering rules.", - ) - - model_config = ConfigDict(populate_by_name=True) - - -class UpdateRulesResponse(BaseModel): - """Response model for updateRules""" - - data: Optional[List] = None - errors: Optional[List] = None - meta: Optional["UpdateRulesResponseMeta"] = Field(default_factory=dict) - - model_config = ConfigDict(populate_by_name=True) - - -class UpdateRulesResponseMeta(BaseModel): - """Nested model for UpdateRulesResponseMeta""" - - next_token: Optional[str] = None - result_count: Optional[int] = None - sent: Optional[str] = None - summary: Any = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getSpacesBuyers - - -class GetSpacesBuyersResponse(BaseModel): - """Response model for getSpacesBuyers""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetSpacesBuyersResponseIncludes"] = None - meta: Optional["GetSpacesBuyersResponseMeta"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetSpacesBuyersResponseIncludes(BaseModel): - """Nested model for GetSpacesBuyersResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetSpacesBuyersResponseMeta(BaseModel): - """Nested model for GetSpacesBuyersResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getPostsByIds - - -class GetPostsByIdsResponse(BaseModel): - """Response model for getPostsByIds""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetPostsByIdsResponseIncludes"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsByIdsResponseIncludes(BaseModel): - """Nested model for GetPostsByIdsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for createPosts - - -class CreatePostsRequest(BaseModel): - """Request model for createPosts""" - - card_uri: Optional[str] = None - community_id: Optional[str] = None - direct_message_deep_link: Optional[str] = None - for_super_followers_only: Optional[bool] = None - geo: Optional["CreatePostsRequestGeo"] = None - media: Optional["CreatePostsRequestMedia"] = Field( - description="Media information being attached to created Tweet. This is mutually exclusive from Quote Tweet Id, Poll, and Card URI.", - default_factory=dict, - ) - nullcast: Optional[bool] = None - poll: Optional["CreatePostsRequestPoll"] = Field( - description="Poll options for a Tweet with a poll. This is mutually exclusive from Media, Quote Tweet Id, and Card URI.", - default_factory=dict, - ) - quote_tweet_id: Optional[str] = None - reply: Optional["CreatePostsRequestReply"] = Field( - description="Tweet information of the Tweet being replied to.", - default_factory=dict, - ) - reply_settings: Optional[str] = None - share_with_followers: Optional[bool] = None - text: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class CreatePostsResponse(BaseModel): - """Response model for createPosts""" - - data: Optional["CreatePostsResponseData"] = Field(default_factory=dict) - errors: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class CreatePostsRequestGeo(BaseModel): - """Nested model for CreatePostsRequestGeo""" - - place_id: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class CreatePostsRequestMedia(BaseModel): - """Nested model for CreatePostsRequestMedia""" - - media_ids: Optional[List] = None - tagged_user_ids: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class CreatePostsRequestPoll(BaseModel): - """Nested model for CreatePostsRequestPoll""" - - duration_minutes: Optional[int] = None - options: Optional[List] = None - reply_settings: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class CreatePostsRequestReply(BaseModel): - """Nested model for CreatePostsRequestReply""" - - exclude_reply_user_ids: Optional[List] = None - in_reply_to_tweet_id: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class CreatePostsResponseData(BaseModel): - """Nested model for CreatePostsResponseData""" - - id: Optional[str] = None - text: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getUsersTimeline - - -class GetUsersTimelineResponse(BaseModel): - """Response model for getUsersTimeline""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetUsersTimelineResponseIncludes"] = None - meta: Optional["GetUsersTimelineResponseMeta"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetUsersTimelineResponseIncludes(BaseModel): - """Nested model for GetUsersTimelineResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetUsersTimelineResponseMeta(BaseModel): - """Nested model for GetUsersTimelineResponseMeta""" - - newest_id: Optional[str] = None - next_token: Optional[str] = None - oldest_id: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getUsersMentions - - -class GetUsersMentionsResponse(BaseModel): - """Response model for getUsersMentions""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetUsersMentionsResponseIncludes"] = None - meta: Optional["GetUsersMentionsResponseMeta"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetUsersMentionsResponseIncludes(BaseModel): - """Nested model for GetUsersMentionsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetUsersMentionsResponseMeta(BaseModel): - """Nested model for GetUsersMentionsResponseMeta""" - - newest_id: Optional[str] = None - next_token: Optional[str] = None - oldest_id: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getInsightsHistorical - - -class GetInsightsHistoricalResponse(BaseModel): - """Response model for getInsightsHistorical""" - - data: Optional[List] = None - errors: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getPostsCountsRecent - - -class GetPostsCountsRecentResponse(BaseModel): - """Response model for getPostsCountsRecent""" - - data: Optional[List] = None - errors: Optional[List] = None - meta: Optional["GetPostsCountsRecentResponseMeta"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsCountsRecentResponseMeta(BaseModel): - """Nested model for GetPostsCountsRecentResponseMeta""" - - newest_id: Optional[str] = None - next_token: Optional[str] = None - oldest_id: Optional[str] = None - total_tweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for streamPostsFirehoseKo - - -class StreamPostsFirehoseKoResponse(BaseModel): - """Response model for streamPostsFirehoseKo""" - - data: Optional["StreamPostsFirehoseKoResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreamPostsFirehoseKoResponseIncludes"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseKoResponseData(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseData""" - - attachments: Optional["StreamPostsFirehoseKoResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreamPostsFirehoseKoResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreamPostsFirehoseKoResponseDataEntities"] = None - geo: Optional["StreamPostsFirehoseKoResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional[ - "StreamPostsFirehoseKoResponseDataNonPublicMetrics" - ] = None - note_tweet: Optional["StreamPostsFirehoseKoResponseDataNoteTweet"] = None - organic_metrics: Optional["StreamPostsFirehoseKoResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreamPostsFirehoseKoResponseDataPromotedMetrics"] = ( - None - ) - public_metrics: Optional["StreamPostsFirehoseKoResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreamPostsFirehoseKoResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreamPostsFirehoseKoResponseDataWithheld"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseKoResponseDataAttachments(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseKoResponseDataEditControls(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseKoResponseDataEntities(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseKoResponseDataGeo(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataGeo""" - - coordinates: Optional["StreamPostsFirehoseKoResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseKoResponseDataGeoCoordinates(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseKoResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseKoResponseDataNoteTweet(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataNoteTweet""" - - entities: Optional["StreamPostsFirehoseKoResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseKoResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseKoResponseDataOrganicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseKoResponseDataPromotedMetrics(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseKoResponseDataPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseKoResponseDataScopes(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataScopes""" - - followers: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseKoResponseDataWithheld(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseKoResponseIncludes(BaseModel): - """Nested model for StreamPostsFirehoseKoResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getPostsAnalytics - - -class GetPostsAnalyticsResponse(BaseModel): - """Response model for getPostsAnalytics""" - - data: Optional[List] = None - errors: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getRuleCounts - - -class GetRuleCountsResponse(BaseModel): - """Response model for getRuleCounts""" - - data: Optional["GetRuleCountsResponseData"] = None - errors: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetRuleCountsResponseData(BaseModel): - """Nested model for GetRuleCountsResponseData""" - - all_project_client_apps: Optional[List] = None - cap_per_client_app: Optional[int] = None - cap_per_project: Optional[int] = None - client_app_rules_count: Optional["GetRuleCountsResponseDataClientAppRulesCount"] = ( - None - ) - project_rules_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetRuleCountsResponseDataClientAppRulesCount(BaseModel): - """Nested model for GetRuleCountsResponseDataClientAppRulesCount""" - - client_app_id: Optional[str] = None - rule_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getPostsQuotedPosts - - -class GetPostsQuotedPostsResponse(BaseModel): - """Response model for getPostsQuotedPosts""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetPostsQuotedPostsResponseIncludes"] = None - meta: Optional["GetPostsQuotedPostsResponseMeta"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsQuotedPostsResponseIncludes(BaseModel): - """Nested model for GetPostsQuotedPostsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsQuotedPostsResponseMeta(BaseModel): - """Nested model for GetPostsQuotedPostsResponseMeta""" - - next_token: Optional[str] = None - result_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for streamPostsFirehose - - -class StreamPostsFirehoseResponse(BaseModel): - """Response model for streamPostsFirehose""" - - data: Optional["StreamPostsFirehoseResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreamPostsFirehoseResponseIncludes"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseResponseData(BaseModel): - """Nested model for StreamPostsFirehoseResponseData""" - - attachments: Optional["StreamPostsFirehoseResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreamPostsFirehoseResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreamPostsFirehoseResponseDataEntities"] = None - geo: Optional["StreamPostsFirehoseResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional["StreamPostsFirehoseResponseDataNonPublicMetrics"] = ( - None - ) - note_tweet: Optional["StreamPostsFirehoseResponseDataNoteTweet"] = None - organic_metrics: Optional["StreamPostsFirehoseResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreamPostsFirehoseResponseDataPromotedMetrics"] = None - public_metrics: Optional["StreamPostsFirehoseResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreamPostsFirehoseResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreamPostsFirehoseResponseDataWithheld"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseResponseDataAttachments(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseResponseDataEditControls(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseResponseDataEntities(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseResponseDataGeo(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataGeo""" - - coordinates: Optional["StreamPostsFirehoseResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseResponseDataGeoCoordinates(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseResponseDataNoteTweet(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataNoteTweet""" - - entities: Optional["StreamPostsFirehoseResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseResponseDataOrganicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseResponseDataPromotedMetrics(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseResponseDataPublicMetrics(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseResponseDataScopes(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataScopes""" - - followers: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseResponseDataWithheld(BaseModel): - """Nested model for StreamPostsFirehoseResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsFirehoseResponseIncludes(BaseModel): - """Nested model for StreamPostsFirehoseResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getInsights28Hr - - -class GetInsights28HrResponse(BaseModel): - """Response model for getInsights28Hr""" - - data: Optional[List] = None - errors: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getPostsReposts - - -class GetPostsRepostsResponse(BaseModel): - """Response model for getPostsReposts""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetPostsRepostsResponseIncludes"] = None - meta: Optional["GetPostsRepostsResponseMeta"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsRepostsResponseIncludes(BaseModel): - """Nested model for GetPostsRepostsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsRepostsResponseMeta(BaseModel): - """Nested model for GetPostsRepostsResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for streamPostsSample10 - - -class StreamPostsSample10Response(BaseModel): - """Response model for streamPostsSample10""" - - data: Optional["StreamPostsSample10ResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreamPostsSample10ResponseIncludes"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSample10ResponseData(BaseModel): - """Nested model for StreamPostsSample10ResponseData""" - - attachments: Optional["StreamPostsSample10ResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreamPostsSample10ResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreamPostsSample10ResponseDataEntities"] = None - geo: Optional["StreamPostsSample10ResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional["StreamPostsSample10ResponseDataNonPublicMetrics"] = ( - None - ) - note_tweet: Optional["StreamPostsSample10ResponseDataNoteTweet"] = None - organic_metrics: Optional["StreamPostsSample10ResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreamPostsSample10ResponseDataPromotedMetrics"] = None - public_metrics: Optional["StreamPostsSample10ResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreamPostsSample10ResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreamPostsSample10ResponseDataWithheld"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSample10ResponseDataAttachments(BaseModel): - """Nested model for StreamPostsSample10ResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSample10ResponseDataEditControls(BaseModel): - """Nested model for StreamPostsSample10ResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSample10ResponseDataEntities(BaseModel): - """Nested model for StreamPostsSample10ResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSample10ResponseDataGeo(BaseModel): - """Nested model for StreamPostsSample10ResponseDataGeo""" - - coordinates: Optional["StreamPostsSample10ResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSample10ResponseDataGeoCoordinates(BaseModel): - """Nested model for StreamPostsSample10ResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSample10ResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreamPostsSample10ResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSample10ResponseDataNoteTweet(BaseModel): - """Nested model for StreamPostsSample10ResponseDataNoteTweet""" - - entities: Optional["StreamPostsSample10ResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSample10ResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreamPostsSample10ResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSample10ResponseDataOrganicMetrics(BaseModel): - """Nested model for StreamPostsSample10ResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSample10ResponseDataPromotedMetrics(BaseModel): - """Nested model for StreamPostsSample10ResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSample10ResponseDataPublicMetrics(BaseModel): - """Nested model for StreamPostsSample10ResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSample10ResponseDataScopes(BaseModel): - """Nested model for StreamPostsSample10ResponseDataScopes""" - - followers: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSample10ResponseDataWithheld(BaseModel): - """Nested model for StreamPostsSample10ResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsSample10ResponseIncludes(BaseModel): - """Nested model for StreamPostsSample10ResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for repostPost - - -class RepostPostRequest(BaseModel): - """Request model for repostPost""" - - tweet_id: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class RepostPostResponse(BaseModel): - """Response model for repostPost""" - - data: Optional["RepostPostResponseData"] = None - errors: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class RepostPostResponseData(BaseModel): - """Nested model for RepostPostResponseData""" - - id: Optional[str] = None - retweeted: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for searchPostsAll - - -class SearchPostsAllResponse(BaseModel): - """Response model for searchPostsAll""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["SearchPostsAllResponseIncludes"] = None - meta: Optional["SearchPostsAllResponseMeta"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class SearchPostsAllResponseIncludes(BaseModel): - """Nested model for SearchPostsAllResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class SearchPostsAllResponseMeta(BaseModel): - """Nested model for SearchPostsAllResponseMeta""" - - newest_id: Optional[str] = None - next_token: Optional[str] = None - oldest_id: Optional[str] = None - result_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for unrepostPost - - -class UnrepostPostResponse(BaseModel): - """Response model for unrepostPost""" - - data: Optional["UnrepostPostResponseData"] = None - errors: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class UnrepostPostResponseData(BaseModel): - """Nested model for UnrepostPostResponseData""" - - retweeted: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for streamPosts - - -class StreamPostsResponse(BaseModel): - """Response model for streamPosts""" - - data: Optional["StreamPostsResponseData"] = None - errors: Optional[List] = None - includes: Optional["StreamPostsResponseIncludes"] = None - matching_rules: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsResponseData(BaseModel): - """Nested model for StreamPostsResponseData""" - - attachments: Optional["StreamPostsResponseDataAttachments"] = None - author_id: Optional[str] = None - community_id: Optional[str] = None - context_annotations: Optional[List] = None - conversation_id: Optional[str] = None - created_at: Optional[str] = None - display_text_range: Optional[List] = None - edit_controls: Optional["StreamPostsResponseDataEditControls"] = None - edit_history_tweet_ids: Optional[List] = None - entities: Optional["StreamPostsResponseDataEntities"] = None - geo: Optional["StreamPostsResponseDataGeo"] = None - id: Optional[str] = None - in_reply_to_user_id: Optional[str] = None - lang: Optional[str] = None - non_public_metrics: Optional["StreamPostsResponseDataNonPublicMetrics"] = None - note_tweet: Optional["StreamPostsResponseDataNoteTweet"] = None - organic_metrics: Optional["StreamPostsResponseDataOrganicMetrics"] = None - possibly_sensitive: Optional[bool] = None - promoted_metrics: Optional["StreamPostsResponseDataPromotedMetrics"] = None - public_metrics: Optional["StreamPostsResponseDataPublicMetrics"] = None - referenced_tweets: Optional[List] = None - reply_settings: Optional[str] = None - scopes: Optional["StreamPostsResponseDataScopes"] = None - source: Optional[str] = None - text: Optional[str] = None - username: Optional[str] = None - withheld: Optional["StreamPostsResponseDataWithheld"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsResponseDataAttachments(BaseModel): - """Nested model for StreamPostsResponseDataAttachments""" - - media_keys: Optional[List] = None - media_source_tweet_id: Optional[List] = None - poll_ids: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsResponseDataEditControls(BaseModel): - """Nested model for StreamPostsResponseDataEditControls""" - - editable_until: Optional[str] = None - edits_remaining: Optional[int] = None - is_edit_eligible: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsResponseDataEntities(BaseModel): - """Nested model for StreamPostsResponseDataEntities""" - - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsResponseDataGeo(BaseModel): - """Nested model for StreamPostsResponseDataGeo""" - - coordinates: Optional["StreamPostsResponseDataGeoCoordinates"] = None - place_id: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsResponseDataGeoCoordinates(BaseModel): - """Nested model for StreamPostsResponseDataGeoCoordinates""" - - coordinates: Optional[List] = None - type: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsResponseDataNonPublicMetrics(BaseModel): - """Nested model for StreamPostsResponseDataNonPublicMetrics""" - - impression_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsResponseDataNoteTweet(BaseModel): - """Nested model for StreamPostsResponseDataNoteTweet""" - - entities: Optional["StreamPostsResponseDataNoteTweetEntities"] = None - text: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsResponseDataNoteTweetEntities(BaseModel): - """Nested model for StreamPostsResponseDataNoteTweetEntities""" - - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsResponseDataOrganicMetrics(BaseModel): - """Nested model for StreamPostsResponseDataOrganicMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsResponseDataPromotedMetrics(BaseModel): - """Nested model for StreamPostsResponseDataPromotedMetrics""" - - impression_count: Optional[int] = None - like_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsResponseDataPublicMetrics(BaseModel): - """Nested model for StreamPostsResponseDataPublicMetrics""" - - bookmark_count: Optional[int] = None - impression_count: Optional[int] = None - like_count: Optional[int] = None - quote_count: Optional[int] = None - reply_count: Optional[int] = None - retweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsResponseDataScopes(BaseModel): - """Nested model for StreamPostsResponseDataScopes""" - - followers: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsResponseDataWithheld(BaseModel): - """Nested model for StreamPostsResponseDataWithheld""" - - copyright: Optional[bool] = None - country_codes: Optional[List] = None - scope: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class StreamPostsResponseIncludes(BaseModel): - """Nested model for StreamPostsResponseIncludes""" - - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for likePost - - -class LikePostRequest(BaseModel): - """Request model for likePost""" - - tweet_id: Optional[str] = None - - model_config = ConfigDict(populate_by_name=True) - - -class LikePostResponse(BaseModel): - """Response model for likePost""" - - data: Optional["LikePostResponseData"] = None - errors: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class LikePostResponseData(BaseModel): - """Nested model for LikePostResponseData""" - - liked: Optional[bool] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getPostsCountsAll - - -class GetPostsCountsAllResponse(BaseModel): - """Response model for getPostsCountsAll""" - - data: Optional[List] = None - errors: Optional[List] = None - meta: Optional["GetPostsCountsAllResponseMeta"] = None - - model_config = ConfigDict(populate_by_name=True) - - -class GetPostsCountsAllResponseMeta(BaseModel): - """Nested model for GetPostsCountsAllResponseMeta""" - - newest_id: Optional[str] = None - next_token: Optional[str] = None - oldest_id: Optional[str] = None - total_tweet_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) diff --git a/xdk/python/xdk/usage/__init__.py b/xdk/python/xdk/usage/__init__.py index 2502c9de..5f38968a 100644 --- a/xdk/python/xdk/usage/__init__.py +++ b/xdk/python/xdk/usage/__init__.py @@ -1,7 +1,7 @@ """ -Usage module for the X API. +usage module for the X API. -This module provides access to the Usage endpoints of the X API. +This module provides access to the usage endpoints of the X API. """ from .client import UsageClient diff --git a/xdk/python/xdk/usage/client.py b/xdk/python/xdk/usage/client.py index 37b53ca0..a1c5692a 100644 --- a/xdk/python/xdk/usage/client.py +++ b/xdk/python/xdk/usage/client.py @@ -1,7 +1,7 @@ """ -Usage client for the X API. +usage client for the X API. -This module provides a client for interacting with the Usage endpoints of the X API. +This module provides a client for interacting with the usage endpoints of the X API. """ from __future__ import annotations @@ -12,32 +12,29 @@ if TYPE_CHECKING: from ..client import Client from .models import ( - GetUsageResponse, + GetResponse, ) class UsageClient: - """Client for Usage operations""" + """Client for usage operations""" def __init__(self, client: Client): self.client = client - def get_usage( + def get( self, days: int = None, - usage_fields: List = None, - ) -> GetUsageResponse: + ) -> GetResponse: """ Get usage Retrieves usage statistics for Posts over a specified number of days. Args: days: The number of days for which you need usage for. - Args: - usage_fields: A comma separated list of Usage fields to display. Returns: - GetUsageResponse: Response data + GetResponse: Response data """ url = self.client.base_url + "/2/usage/tweets" if self.client.bearer_token: @@ -51,8 +48,6 @@ def get_usage( params = {} if days is not None: params["days"] = days - if usage_fields is not None: - params["usage.fields"] = ",".join(str(item) for item in usage_fields) headers = {} # Make the request response = self.client.session.get( @@ -65,4 +60,4 @@ def get_usage( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetUsageResponse.model_validate(response_data) + return GetResponse.model_validate(response_data) diff --git a/xdk/python/xdk/usage/models.py b/xdk/python/xdk/usage/models.py index ed56b329..3d00d445 100644 --- a/xdk/python/xdk/usage/models.py +++ b/xdk/python/xdk/usage/models.py @@ -1,7 +1,7 @@ """ -Usage models for the X API. +usage models for the X API. -This module provides models for the Usage endpoints of the X API. +This module provides models for the usage endpoints of the X API. """ from typing import Dict, List, Optional, Any, Union, Literal @@ -9,24 +9,24 @@ from datetime import datetime -# Models for getUsage +# Models for get -class GetUsageResponse(BaseModel): - """Response model for getUsage""" +class GetResponse(BaseModel): + """Response model for get""" - data: Optional["GetUsageResponseData"] = None + data: Optional["GetResponseData"] = None errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class GetUsageResponseData(BaseModel): - """Nested model for GetUsageResponseData""" +class GetResponseData(BaseModel): + """Nested model for GetResponseData""" cap_reset_day: Optional[int] = None daily_client_app_usage: Optional[List] = None - daily_project_usage: Optional["GetUsageResponseDataDailyProjectUsage"] = None + daily_project_usage: Optional["GetResponseDataDailyProjectUsage"] = None project_cap: Optional[int] = None project_id: Optional[str] = None project_usage: Optional[int] = None @@ -34,8 +34,8 @@ class GetUsageResponseData(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetUsageResponseDataDailyProjectUsage(BaseModel): - """Nested model for GetUsageResponseDataDailyProjectUsage""" +class GetResponseDataDailyProjectUsage(BaseModel): + """Nested model for GetResponseDataDailyProjectUsage""" project_id: Optional[int] = None usage: Optional[List] = None diff --git a/xdk/python/xdk/users/__init__.py b/xdk/python/xdk/users/__init__.py index f316d37d..8e19cbc0 100644 --- a/xdk/python/xdk/users/__init__.py +++ b/xdk/python/xdk/users/__init__.py @@ -1,7 +1,7 @@ """ -Users module for the X API. +users module for the X API. -This module provides access to the Users endpoints of the X API. +This module provides access to the users endpoints of the X API. """ from .client import UsersClient diff --git a/xdk/python/xdk/users/client.py b/xdk/python/xdk/users/client.py index 8afba7b3..638e2af6 100644 --- a/xdk/python/xdk/users/client.py +++ b/xdk/python/xdk/users/client.py @@ -1,7 +1,7 @@ """ -Users client for the X API. +users client for the X API. -This module provides a client for interacting with the Users endpoints of the X API. +This module provides a client for interacting with the users endpoints of the X API. """ from __future__ import annotations @@ -12,68 +12,63 @@ if TYPE_CHECKING: from ..client import Client from .models import ( - GetListsFollowersResponse, - GetUsersMutingResponse, + GetFollowedListsResponse, + GetListMembershipsResponse, + GetRepostsOfMeResponse, + GetOwnedListsResponse, + GetPostsResponse, + GetLikedPostsResponse, + GetTimelineResponse, + GetByUsernamesResponse, + GetMentionsResponse, + SearchResponse, + GetMutingResponse, MuteUserRequest, MuteUserResponse, - GetMyUserResponse, - GetUsersRepostsOfMeResponse, - SearchUsersResponse, - GetUsersByIdsResponse, - GetUsersBlockingResponse, - BlockUsersDmsResponse, - GetUsersByUsernameResponse, - GetUsersFollowingResponse, + UnblockDmsResponse, + UnmuteUserResponse, + GetBookmarksResponse, + GetByIdsResponse, + GetFollowingResponse, FollowUserRequest, FollowUserResponse, - UnmuteUserResponse, - UnblockUsersDmsResponse, + GetMeResponse, + GetByIdResponse, + GetBlockingResponse, + BlockDmsResponse, UnfollowUserResponse, - GetListsMembersResponse, - GetPostsRepostedByResponse, - GetUsersByIdResponse, - GetUsersByUsernamesResponse, - GetPostsLikingUsersResponse, - GetUsersFollowersResponse, + GetFollowersResponse, + GetByUsernameResponse, ) class UsersClient: - """Client for Users operations""" + """Client for users operations""" def __init__(self, client: Client): self.client = client - def get_lists_followers( + def get_followed_lists( self, - id: str, + id: Any, max_results: int = None, - pagination_token: str = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetListsFollowersResponse: + pagination_token: Any = None, + ) -> GetFollowedListsResponse: """ - Get List followers - Retrieves a list of Users who follow a specific List by its ID. + Get followed Lists + Retrieves a list of Lists followed by a specific User by their ID. Args: - id: The ID of the List. + id: The ID of the User to lookup. Args: max_results: The maximum number of results. Args: pagination_token: This parameter is used to get a specified 'page' of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. Returns: - GetListsFollowersResponse: Response data + GetFollowedListsResponse: Response data """ - url = self.client.base_url + "/2/lists/{id}/followers" + url = self.client.base_url + "/2/users/{id}/followed_lists" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -92,12 +87,6 @@ def get_lists_followers( params["max_results"] = max_results if pagination_token is not None: params["pagination_token"] = pagination_token - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) url = url.replace("{id}", str(id)) headers = {} # Make the request @@ -111,37 +100,36 @@ def get_lists_followers( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetListsFollowersResponse.model_validate(response_data) + return GetFollowedListsResponse.model_validate(response_data) - def get_users_muting( + def get_list_memberships( self, - id: str, + id: Any, max_results: int = None, - pagination_token: str = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetUsersMutingResponse: + pagination_token: Any = None, + ) -> GetListMembershipsResponse: """ - Get muting - Retrieves a list of Users muted by the authenticated user. + Get List memberships + Retrieves a list of Lists that a specific User is a member of by their ID. Args: - id: The ID of the authenticated source User for whom to return results. + id: The ID of the User to lookup. Args: max_results: The maximum number of results. Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. + pagination_token: This parameter is used to get a specified 'page' of results. Returns: - GetUsersMutingResponse: Response data + GetListMembershipsResponse: Response data """ - url = self.client.base_url + "/2/users/{id}/muting" + url = self.client.base_url + "/2/users/{id}/list_memberships" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh @@ -152,146 +140,27 @@ def get_users_muting( params["max_results"] = max_results if pagination_token is not None: params["pagination_token"] = pagination_token - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{id}", str(id)) - headers = {} - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return GetUsersMutingResponse.model_validate(response_data) - - - def mute_user( - self, - id: str, - body: Optional[MuteUserRequest] = None, - ) -> MuteUserResponse: - """ - Mute User - Causes the authenticated user to mute a specific User by their ID. - Args: - id: The ID of the authenticated source User that is requesting to mute the target User. - body: Request body - Returns: - MuteUserResponse: Response data - """ - url = self.client.base_url + "/2/users/{id}/muting" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} url = url.replace("{id}", str(id)) headers = {} - headers["Content-Type"] = "application/json" - # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - else: - response = self.client.session.post( - url, - params=params, - headers=headers, - json=body.model_dump(exclude_none=True) if body else None, - ) - # Check for errors - response.raise_for_status() - # Parse the response data - response_data = response.json() - # Convert to Pydantic model if applicable - return MuteUserResponse.model_validate(response_data) - - - def get_my_user( - self, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetMyUserResponse: - """ - Get my User - Retrieves details of the authenticated user. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Returns: - GetMyUserResponse: Response data - """ - url = self.client.base_url + "/2/users/me" - # Ensure we have a valid access token - if self.client.oauth2_auth and self.client.token: - # Check if token needs refresh - if self.client.is_token_expired(): - self.client.refresh_token() - params = {} - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - headers = {} # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) + response = self.client.session.get( + url, + params=params, + headers=headers, + ) # Check for errors response.raise_for_status() # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetMyUserResponse.model_validate(response_data) + return GetListMembershipsResponse.model_validate(response_data) - def get_users_reposts_of_me( + def get_reposts_of_me( self, max_results: int = None, - pagination_token: str = None, - tweet_fields: List = None, - expansions: List = None, - media_fields: List = None, - poll_fields: List = None, - user_fields: List = None, - place_fields: List = None, - ) -> GetUsersRepostsOfMeResponse: + pagination_token: Any = None, + ) -> GetRepostsOfMeResponse: """ Get Reposts of me Retrieves a list of Posts that repost content from the authenticated user. @@ -299,20 +168,8 @@ def get_users_reposts_of_me( max_results: The maximum number of results. Args: pagination_token: This parameter is used to get the next 'page' of results. - Args: - tweet_fields: A comma separated list of Tweet fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - media_fields: A comma separated list of Media fields to display. - Args: - poll_fields: A comma separated list of Poll fields to display. - Args: - user_fields: A comma separated list of User fields to display. - Args: - place_fields: A comma separated list of Place fields to display. Returns: - GetUsersRepostsOfMeResponse: Response data + GetRepostsOfMeResponse: Response data """ url = self.client.base_url + "/2/users/reposts_of_me" # Ensure we have a valid access token @@ -325,18 +182,6 @@ def get_users_reposts_of_me( params["max_results"] = max_results if pagination_token is not None: params["pagination_token"] = pagination_token - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if media_fields is not None: - params["media.fields"] = ",".join(str(item) for item in media_fields) - if poll_fields is not None: - params["poll.fields"] = ",".join(str(item) for item in poll_fields) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if place_fields is not None: - params["place.fields"] = ",".join(str(item) for item in place_fields) headers = {} # Make the request if self.client.oauth2_session: @@ -356,99 +201,96 @@ def get_users_reposts_of_me( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetUsersRepostsOfMeResponse.model_validate(response_data) + return GetRepostsOfMeResponse.model_validate(response_data) - def search_users( + def get_owned_lists( self, - query: str, + id: Any, max_results: int = None, - next_token: str = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> SearchUsersResponse: + pagination_token: Any = None, + ) -> GetOwnedListsResponse: """ - Search Users - Retrieves a list of Users matching a search query. + Get owned Lists + Retrieves a list of Lists owned by a specific User by their ID. Args: - query: TThe the query string by which to query for users. + id: The ID of the User to lookup. Args: max_results: The maximum number of results. Args: - next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. + pagination_token: This parameter is used to get a specified 'page' of results. Returns: - SearchUsersResponse: Response data + GetOwnedListsResponse: Response data """ - url = self.client.base_url + "/2/users/search" + url = self.client.base_url + "/2/users/{id}/owned_lists" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} - if query is not None: - params["query"] = query if max_results is not None: params["max_results"] = max_results - if next_token is not None: - params["next_token"] = next_token - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) + if pagination_token is not None: + params["pagination_token"] = pagination_token + url = url.replace("{id}", str(id)) headers = {} # Make the request - if self.client.oauth2_session: - response = self.client.oauth2_session.get( - url, - params=params, - headers=headers, - ) - else: - response = self.client.session.get( - url, - params=params, - headers=headers, - ) + response = self.client.session.get( + url, + params=params, + headers=headers, + ) # Check for errors response.raise_for_status() # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return SearchUsersResponse.model_validate(response_data) + return GetOwnedListsResponse.model_validate(response_data) - def get_users_by_ids( + def get_posts( self, - ids: List, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetUsersByIdsResponse: + id: Any, + since_id: Any = None, + until_id: Any = None, + max_results: int = None, + pagination_token: Any = None, + exclude: List = None, + start_time: str = None, + end_time: str = None, + ) -> GetPostsResponse: """ - Get Users by IDs - Retrieves details of multiple Users by their IDs. + Get Posts + Retrieves a list of posts authored by a specific User by their ID. Args: - ids: A list of User IDs, comma-separated. You can specify up to 100 IDs. + id: The ID of the User to lookup. + Args: + since_id: The minimum Post ID to be included in the result set. This parameter takes precedence over start_time if both are specified. + Args: + until_id: The maximum Post ID to be included in the result set. This parameter takes precedence over end_time if both are specified. + Args: + max_results: The maximum number of results. + Args: + pagination_token: This parameter is used to get the next 'page' of results. Args: - user_fields: A comma separated list of User fields to display. + exclude: The set of entities to exclude (e.g. 'replies' or 'retweets'). Args: - expansions: A comma separated list of fields to expand. + start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Posts will be provided. The since_id parameter takes precedence if it is also specified. Args: - tweet_fields: A comma separated list of Tweet fields to display. + end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. The until_id parameter takes precedence if it is also specified. Returns: - GetUsersByIdsResponse: Response data + GetPostsResponse: Response data """ - url = self.client.base_url + "/2/users" + url = self.client.base_url + "/2/users/{id}/tweets" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -463,14 +305,21 @@ def get_users_by_ids( if self.client.is_token_expired(): self.client.refresh_token() params = {} - if ids is not None: - params["ids"] = ",".join(str(item) for item in ids) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) + if since_id is not None: + params["since_id"] = since_id + if until_id is not None: + params["until_id"] = until_id + if max_results is not None: + params["max_results"] = max_results + if pagination_token is not None: + params["pagination_token"] = pagination_token + if exclude is not None: + params["exclude"] = ",".join(str(item) for item in exclude) + if start_time is not None: + params["start_time"] = start_time + if end_time is not None: + params["end_time"] = end_time + url = url.replace("{id}", str(id)) headers = {} # Make the request response = self.client.session.get( @@ -483,37 +332,28 @@ def get_users_by_ids( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetUsersByIdsResponse.model_validate(response_data) + return GetPostsResponse.model_validate(response_data) - def get_users_blocking( + def get_liked_posts( self, - id: str, + id: Any, max_results: int = None, - pagination_token: str = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetUsersBlockingResponse: + pagination_token: Any = None, + ) -> GetLikedPostsResponse: """ - Get blocking - Retrieves a list of Users blocked by the specified User ID. + Get liked Posts + Retrieves a list of Posts liked by a specific User by their ID. Args: - id: The ID of the authenticated source User for whom to return results. + id: The ID of the User to lookup. Args: max_results: The maximum number of results. Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. + pagination_token: This parameter is used to get the next 'page' of results. Returns: - GetUsersBlockingResponse: Response data + GetLikedPostsResponse: Response data """ - url = self.client.base_url + "/2/users/{id}/blocking" + url = self.client.base_url + "/2/users/{id}/liked_tweets" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh @@ -524,12 +364,6 @@ def get_users_blocking( params["max_results"] = max_results if pagination_token is not None: params["pagination_token"] = pagination_token - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) url = url.replace("{id}", str(id)) headers = {} # Make the request @@ -550,39 +384,74 @@ def get_users_blocking( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetUsersBlockingResponse.model_validate(response_data) + return GetLikedPostsResponse.model_validate(response_data) - def block_users_dms( + def get_timeline( self, - id: str, - ) -> BlockUsersDmsResponse: + id: Any, + since_id: Any = None, + until_id: Any = None, + max_results: int = None, + pagination_token: Any = None, + exclude: List = None, + start_time: str = None, + end_time: str = None, + ) -> GetTimelineResponse: """ - Block DMs - Blocks direct messages to or from a specific User by their ID for the authenticated user. + Get Timeline + Retrieves a reverse chronological list of Posts in the authenticated User’s Timeline. Args: - id: The ID of the target User that the authenticated user requesting to block dms for. + id: The ID of the authenticated source User to list Reverse Chronological Timeline Posts of. + Args: + since_id: The minimum Post ID to be included in the result set. This parameter takes precedence over start_time if both are specified. + Args: + until_id: The maximum Post ID to be included in the result set. This parameter takes precedence over end_time if both are specified. + Args: + max_results: The maximum number of results. + Args: + pagination_token: This parameter is used to get the next 'page' of results. + Args: + exclude: The set of entities to exclude (e.g. 'replies' or 'retweets'). + Args: + start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Posts will be provided. The since_id parameter takes precedence if it is also specified. + Args: + end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. The until_id parameter takes precedence if it is also specified. Returns: - BlockUsersDmsResponse: Response data + GetTimelineResponse: Response data """ - url = self.client.base_url + "/2/users/{id}/dm/block" + url = self.client.base_url + "/2/users/{id}/timelines/reverse_chronological" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} + if since_id is not None: + params["since_id"] = since_id + if until_id is not None: + params["until_id"] = until_id + if max_results is not None: + params["max_results"] = max_results + if pagination_token is not None: + params["pagination_token"] = pagination_token + if exclude is not None: + params["exclude"] = ",".join(str(item) for item in exclude) + if start_time is not None: + params["start_time"] = start_time + if end_time is not None: + params["end_time"] = end_time url = url.replace("{id}", str(id)) headers = {} # Make the request if self.client.oauth2_session: - response = self.client.oauth2_session.post( + response = self.client.oauth2_session.get( url, params=params, headers=headers, ) else: - response = self.client.session.post( + response = self.client.session.get( url, params=params, headers=headers, @@ -592,31 +461,22 @@ def block_users_dms( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return BlockUsersDmsResponse.model_validate(response_data) + return GetTimelineResponse.model_validate(response_data) - def get_users_by_username( + def get_by_usernames( self, - username: str, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetUsersByUsernameResponse: + usernames: List, + ) -> GetByUsernamesResponse: """ - Get User by username - Retrieves details of a specific User by their username. - Args: - username: A username. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. + Get Users by usernames + Retrieves details of multiple Users by their usernames. Args: - tweet_fields: A comma separated list of Tweet fields to display. + usernames: A list of usernames, comma-separated. Returns: - GetUsersByUsernameResponse: Response data + GetByUsernamesResponse: Response data """ - url = self.client.base_url + "/2/users/by/username/{username}" + url = self.client.base_url + "/2/users/by" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -631,13 +491,8 @@ def get_users_by_username( if self.client.is_token_expired(): self.client.refresh_token() params = {} - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{username}", str(username)) + if usernames is not None: + params["usernames"] = ",".join(str(item) for item in usernames) headers = {} # Make the request response = self.client.session.get( @@ -650,37 +505,40 @@ def get_users_by_username( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetUsersByUsernameResponse.model_validate(response_data) + return GetByUsernamesResponse.model_validate(response_data) - def get_users_following( + def get_mentions( self, - id: str, + id: Any, + since_id: Any = None, + until_id: Any = None, max_results: int = None, - pagination_token: str = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetUsersFollowingResponse: + pagination_token: Any = None, + start_time: str = None, + end_time: str = None, + ) -> GetMentionsResponse: """ - Get following - Retrieves a list of Users followed by a specific User by their ID. + Get mentions + Retrieves a list of Posts that mention a specific User by their ID. Args: id: The ID of the User to lookup. Args: - max_results: The maximum number of results. + since_id: The minimum Post ID to be included in the result set. This parameter takes precedence over start_time if both are specified. Args: - pagination_token: This parameter is used to get a specified 'page' of results. + until_id: The maximum Post ID to be included in the result set. This parameter takes precedence over end_time if both are specified. Args: - user_fields: A comma separated list of User fields to display. + max_results: The maximum number of results. + Args: + pagination_token: This parameter is used to get the next 'page' of results. Args: - expansions: A comma separated list of fields to expand. + start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Posts will be provided. The since_id parameter takes precedence if it is also specified. Args: - tweet_fields: A comma separated list of Tweet fields to display. + end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided. The until_id parameter takes precedence if it is also specified. Returns: - GetUsersFollowingResponse: Response data + GetMentionsResponse: Response data """ - url = self.client.base_url + "/2/users/{id}/following" + url = self.client.base_url + "/2/users/{id}/mentions" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -695,16 +553,18 @@ def get_users_following( if self.client.is_token_expired(): self.client.refresh_token() params = {} + if since_id is not None: + params["since_id"] = since_id + if until_id is not None: + params["until_id"] = until_id if max_results is not None: params["max_results"] = max_results if pagination_token is not None: params["pagination_token"] = pagination_token - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) + if start_time is not None: + params["start_time"] = start_time + if end_time is not None: + params["end_time"] = end_time url = url.replace("{id}", str(id)) headers = {} # Make the request @@ -718,90 +578,102 @@ def get_users_following( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetUsersFollowingResponse.model_validate(response_data) + return GetMentionsResponse.model_validate(response_data) - def follow_user( + def search( self, - id: str, - body: Optional[FollowUserRequest] = None, - ) -> FollowUserResponse: + query: Any, + max_results: int = None, + next_token: Any = None, + ) -> SearchResponse: """ - Follow User - Causes the authenticated user to follow a specific user by their ID. + Search Users + Retrieves a list of Users matching a search query. Args: - id: The ID of the authenticated source User that is requesting to follow the target User. - body: Request body + query: TThe the query string by which to query for users. + Args: + max_results: The maximum number of results. + Args: + next_token: This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. Returns: - FollowUserResponse: Response data + SearchResponse: Response data """ - url = self.client.base_url + "/2/users/{id}/following" + url = self.client.base_url + "/2/users/search" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} - url = url.replace("{id}", str(id)) + if query is not None: + params["query"] = query + if max_results is not None: + params["max_results"] = max_results + if next_token is not None: + params["next_token"] = next_token headers = {} - headers["Content-Type"] = "application/json" # Make the request if self.client.oauth2_session: - response = self.client.oauth2_session.post( + response = self.client.oauth2_session.get( url, params=params, headers=headers, - json=body.model_dump(exclude_none=True) if body else None, ) else: - response = self.client.session.post( + response = self.client.session.get( url, params=params, headers=headers, - json=body.model_dump(exclude_none=True) if body else None, ) # Check for errors response.raise_for_status() # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return FollowUserResponse.model_validate(response_data) + return SearchResponse.model_validate(response_data) - def unmute_user( + def get_muting( self, - source_user_id: str, - target_user_id: str, - ) -> UnmuteUserResponse: + id: Any, + max_results: int = None, + pagination_token: Any = None, + ) -> GetMutingResponse: """ - Unmute User - Causes the authenticated user to unmute a specific user by their ID. + Get muting + Retrieves a list of Users muted by the authenticated user. Args: - source_user_id: The ID of the authenticated source User that is requesting to unmute the target User. + id: The ID of the authenticated source User for whom to return results. Args: - target_user_id: The ID of the User that the source User is requesting to unmute. + max_results: The maximum number of results. + Args: + pagination_token: This parameter is used to get the next 'page' of results. Returns: - UnmuteUserResponse: Response data + GetMutingResponse: Response data """ - url = self.client.base_url + "/2/users/{source_user_id}/muting/{target_user_id}" + url = self.client.base_url + "/2/users/{id}/muting" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} - url = url.replace("{source_user_id}", str(source_user_id)) - url = url.replace("{target_user_id}", str(target_user_id)) + if max_results is not None: + params["max_results"] = max_results + if pagination_token is not None: + params["pagination_token"] = pagination_token + url = url.replace("{id}", str(id)) headers = {} # Make the request if self.client.oauth2_session: - response = self.client.oauth2_session.delete( + response = self.client.oauth2_session.get( url, params=params, headers=headers, ) else: - response = self.client.session.delete( + response = self.client.session.get( url, params=params, headers=headers, @@ -811,20 +683,67 @@ def unmute_user( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return UnmuteUserResponse.model_validate(response_data) + return GetMutingResponse.model_validate(response_data) - def unblock_users_dms( + def mute_user( self, - id: str, - ) -> UnblockUsersDmsResponse: + id: Any, + body: Optional[MuteUserRequest] = None, + ) -> MuteUserResponse: + """ + Mute User + Causes the authenticated user to mute a specific User by their ID. + Args: + id: The ID of the authenticated source User that is requesting to mute the target User. + body: Request body + Returns: + MuteUserResponse: Response data + """ + url = self.client.base_url + "/2/users/{id}/muting" + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + url = url.replace("{id}", str(id)) + headers = {} + headers["Content-Type"] = "application/json" + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.post( + url, + params=params, + headers=headers, + json=body.model_dump(exclude_none=True) if body else None, + ) + else: + response = self.client.session.post( + url, + params=params, + headers=headers, + json=body.model_dump(exclude_none=True) if body else None, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return MuteUserResponse.model_validate(response_data) + + + def unblock_dms( + self, + id: Any, + ) -> UnblockDmsResponse: """ Unblock DMs Unblocks direct messages to or from a specific User by their ID for the authenticated user. Args: id: The ID of the target User that the authenticated user requesting to unblock dms for. Returns: - UnblockUsersDmsResponse: Response data + UnblockDmsResponse: Response data """ url = self.client.base_url + "/2/users/{id}/dm/unblock" # Ensure we have a valid access token @@ -853,28 +772,25 @@ def unblock_users_dms( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return UnblockUsersDmsResponse.model_validate(response_data) + return UnblockDmsResponse.model_validate(response_data) - def unfollow_user( + def unmute_user( self, - source_user_id: str, - target_user_id: str, - ) -> UnfollowUserResponse: + source_user_id: Any, + target_user_id: Any, + ) -> UnmuteUserResponse: """ - Unfollow User - Causes the authenticated user to unfollow a specific user by their ID. + Unmute User + Causes the authenticated user to unmute a specific user by their ID. Args: - source_user_id: The ID of the authenticated source User that is requesting to unfollow the target User. + source_user_id: The ID of the authenticated source User that is requesting to unmute the target User. Args: - target_user_id: The ID of the User that the source User is requesting to unfollow. + target_user_id: The ID of the User that the source User is requesting to unmute. Returns: - UnfollowUserResponse: Response data + UnmuteUserResponse: Response data """ - url = ( - self.client.base_url - + "/2/users/{source_user_id}/following/{target_user_id}" - ) + url = self.client.base_url + "/2/users/{source_user_id}/muting/{target_user_id}" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh @@ -902,37 +818,74 @@ def unfollow_user( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return UnfollowUserResponse.model_validate(response_data) + return UnmuteUserResponse.model_validate(response_data) - def get_lists_members( + def get_bookmarks( self, - id: str, + id: Any, max_results: int = None, - pagination_token: str = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetListsMembersResponse: + pagination_token: Any = None, + ) -> GetBookmarksResponse: """ - Get List members - Retrieves a list of Users who are members of a specific List by its ID. + Get Bookmarks + Retrieves a list of Posts bookmarked by the authenticated user. Args: - id: The ID of the List. + id: The ID of the authenticated source User for whom to return results. Args: max_results: The maximum number of results. Args: - pagination_token: This parameter is used to get a specified 'page' of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. + pagination_token: This parameter is used to get the next 'page' of results. + Returns: + GetBookmarksResponse: Response data + """ + url = self.client.base_url + "/2/users/{id}/bookmarks" + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + if max_results is not None: + params["max_results"] = max_results + if pagination_token is not None: + params["pagination_token"] = pagination_token + url = url.replace("{id}", str(id)) + headers = {} + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.get( + url, + params=params, + headers=headers, + ) + else: + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetBookmarksResponse.model_validate(response_data) + + + def get_by_ids( + self, + ids: List, + ) -> GetByIdsResponse: + """ + Get Users by IDs + Retrieves details of multiple Users by their IDs. Args: - tweet_fields: A comma separated list of Tweet fields to display. + ids: A list of User IDs, comma-separated. You can specify up to 100 IDs. Returns: - GetListsMembersResponse: Response data + GetByIdsResponse: Response data """ - url = self.client.base_url + "/2/lists/{id}/members" + url = self.client.base_url + "/2/users" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -947,17 +900,8 @@ def get_lists_members( if self.client.is_token_expired(): self.client.refresh_token() params = {} - if max_results is not None: - params["max_results"] = max_results - if pagination_token is not None: - params["pagination_token"] = pagination_token - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{id}", str(id)) + if ids is not None: + params["ids"] = ",".join(str(item) for item in ids) headers = {} # Make the request response = self.client.session.get( @@ -970,37 +914,28 @@ def get_lists_members( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetListsMembersResponse.model_validate(response_data) + return GetByIdsResponse.model_validate(response_data) - def get_posts_reposted_by( + def get_following( self, - id: str, + id: Any, max_results: int = None, - pagination_token: str = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetPostsRepostedByResponse: + pagination_token: Any = None, + ) -> GetFollowingResponse: """ - Get Reposted by - Retrieves a list of Users who reposted a specific Post by its ID. + Get following + Retrieves a list of Users followed by a specific User by their ID. Args: - id: A single Post ID. + id: The ID of the User to lookup. Args: max_results: The maximum number of results. Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. + pagination_token: This parameter is used to get a specified 'page' of results. Returns: - GetPostsRepostedByResponse: Response data + GetFollowingResponse: Response data """ - url = self.client.base_url + "/2/tweets/{id}/retweeted_by" + url = self.client.base_url + "/2/users/{id}/following" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -1019,12 +954,6 @@ def get_posts_reposted_by( params["max_results"] = max_results if pagination_token is not None: params["pagination_token"] = pagination_token - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) url = url.replace("{id}", str(id)) headers = {} # Make the request @@ -1038,89 +967,107 @@ def get_posts_reposted_by( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetPostsRepostedByResponse.model_validate(response_data) + return GetFollowingResponse.model_validate(response_data) - def get_users_by_id( + def follow_user( self, - id: str, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetUsersByIdResponse: + id: Any, + body: Optional[FollowUserRequest] = None, + ) -> FollowUserResponse: """ - Get User by ID - Retrieves details of a specific User by their ID. - Args: - id: The ID of the User to lookup. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. + Follow User + Causes the authenticated user to follow a specific user by their ID. Args: - tweet_fields: A comma separated list of Tweet fields to display. + id: The ID of the authenticated source User that is requesting to follow the target User. + body: Request body Returns: - GetUsersByIdResponse: Response data + FollowUserResponse: Response data """ - url = self.client.base_url + "/2/users/{id}" - if self.client.bearer_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.bearer_token}" + url = self.client.base_url + "/2/users/{id}/following" + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + url = url.replace("{id}", str(id)) + headers = {} + headers["Content-Type"] = "application/json" + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.post( + url, + params=params, + headers=headers, + json=body.model_dump(exclude_none=True) if body else None, ) - elif self.client.access_token: - self.client.session.headers["Authorization"] = ( - f"Bearer {self.client.access_token}" + else: + response = self.client.session.post( + url, + params=params, + headers=headers, + json=body.model_dump(exclude_none=True) if body else None, ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return FollowUserResponse.model_validate(response_data) + + + def get_me( + self, + ) -> GetMeResponse: + """ + Get my User + Retrieves details of the authenticated user. + Returns: + GetMeResponse: Response data + """ + url = self.client.base_url + "/2/users/me" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh if self.client.is_token_expired(): self.client.refresh_token() params = {} - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) - url = url.replace("{id}", str(id)) headers = {} # Make the request - response = self.client.session.get( - url, - params=params, - headers=headers, - ) + if self.client.oauth2_session: + response = self.client.oauth2_session.get( + url, + params=params, + headers=headers, + ) + else: + response = self.client.session.get( + url, + params=params, + headers=headers, + ) # Check for errors response.raise_for_status() # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetUsersByIdResponse.model_validate(response_data) + return GetMeResponse.model_validate(response_data) - def get_users_by_usernames( + def get_by_id( self, - usernames: List, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetUsersByUsernamesResponse: + id: Any, + ) -> GetByIdResponse: """ - Get Users by usernames - Retrieves details of multiple Users by their usernames. - Args: - usernames: A list of usernames, comma-separated. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. + Get User by ID + Retrieves details of a specific User by their ID. Args: - tweet_fields: A comma separated list of Tweet fields to display. + id: The ID of the User to lookup. Returns: - GetUsersByUsernamesResponse: Response data + GetByIdResponse: Response data """ - url = self.client.base_url + "/2/users/by" + url = self.client.base_url + "/2/users/{id}" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -1135,14 +1082,7 @@ def get_users_by_usernames( if self.client.is_token_expired(): self.client.refresh_token() params = {} - if usernames is not None: - params["usernames"] = ",".join(str(item) for item in usernames) - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) + url = url.replace("{id}", str(id)) headers = {} # Make the request response = self.client.session.get( @@ -1155,37 +1095,28 @@ def get_users_by_usernames( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetUsersByUsernamesResponse.model_validate(response_data) + return GetByIdResponse.model_validate(response_data) - def get_posts_liking_users( + def get_blocking( self, - id: str, + id: Any, max_results: int = None, - pagination_token: str = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetPostsLikingUsersResponse: + pagination_token: Any = None, + ) -> GetBlockingResponse: """ - Get Liking Users - Retrieves a list of Users who liked a specific Post by its ID. + Get blocking + Retrieves a list of Users blocked by the specified User ID. Args: - id: A single Post ID. + id: The ID of the authenticated source User for whom to return results. Args: max_results: The maximum number of results. Args: - pagination_token: This parameter is used to get the next 'page' of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. + pagination_token: This parameter is used to get a specified 'page' of results. Returns: - GetPostsLikingUsersResponse: Response data + GetBlockingResponse: Response data """ - url = self.client.base_url + "/2/tweets/{id}/liking_users" + url = self.client.base_url + "/2/users/{id}/blocking" # Ensure we have a valid access token if self.client.oauth2_auth and self.client.token: # Check if token needs refresh @@ -1196,12 +1127,6 @@ def get_posts_liking_users( params["max_results"] = max_results if pagination_token is not None: params["pagination_token"] = pagination_token - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) url = url.replace("{id}", str(id)) headers = {} # Make the request @@ -1222,18 +1147,106 @@ def get_posts_liking_users( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetPostsLikingUsersResponse.model_validate(response_data) + return GetBlockingResponse.model_validate(response_data) + + + def block_dms( + self, + id: Any, + ) -> BlockDmsResponse: + """ + Block DMs + Blocks direct messages to or from a specific User by their ID for the authenticated user. + Args: + id: The ID of the target User that the authenticated user requesting to block dms for. + Returns: + BlockDmsResponse: Response data + """ + url = self.client.base_url + "/2/users/{id}/dm/block" + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + url = url.replace("{id}", str(id)) + headers = {} + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.post( + url, + params=params, + headers=headers, + ) + else: + response = self.client.session.post( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return BlockDmsResponse.model_validate(response_data) + + + def unfollow_user( + self, + source_user_id: Any, + target_user_id: Any, + ) -> UnfollowUserResponse: + """ + Unfollow User + Causes the authenticated user to unfollow a specific user by their ID. + Args: + source_user_id: The ID of the authenticated source User that is requesting to unfollow the target User. + Args: + target_user_id: The ID of the User that the source User is requesting to unfollow. + Returns: + UnfollowUserResponse: Response data + """ + url = ( + self.client.base_url + + "/2/users/{source_user_id}/following/{target_user_id}" + ) + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + url = url.replace("{source_user_id}", str(source_user_id)) + url = url.replace("{target_user_id}", str(target_user_id)) + headers = {} + # Make the request + if self.client.oauth2_session: + response = self.client.oauth2_session.delete( + url, + params=params, + headers=headers, + ) + else: + response = self.client.session.delete( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return UnfollowUserResponse.model_validate(response_data) - def get_users_followers( + def get_followers( self, - id: str, + id: Any, max_results: int = None, - pagination_token: str = None, - user_fields: List = None, - expansions: List = None, - tweet_fields: List = None, - ) -> GetUsersFollowersResponse: + pagination_token: Any = None, + ) -> GetFollowersResponse: """ Get followers Retrieves a list of Users who follow a specific User by their ID. @@ -1243,14 +1256,8 @@ def get_users_followers( max_results: The maximum number of results. Args: pagination_token: This parameter is used to get a specified 'page' of results. - Args: - user_fields: A comma separated list of User fields to display. - Args: - expansions: A comma separated list of fields to expand. - Args: - tweet_fields: A comma separated list of Tweet fields to display. Returns: - GetUsersFollowersResponse: Response data + GetFollowersResponse: Response data """ url = self.client.base_url + "/2/users/{id}/followers" if self.client.bearer_token: @@ -1271,12 +1278,6 @@ def get_users_followers( params["max_results"] = max_results if pagination_token is not None: params["pagination_token"] = pagination_token - if user_fields is not None: - params["user.fields"] = ",".join(str(item) for item in user_fields) - if expansions is not None: - params["expansions"] = ",".join(str(item) for item in expansions) - if tweet_fields is not None: - params["tweet.fields"] = ",".join(str(item) for item in tweet_fields) url = url.replace("{id}", str(id)) headers = {} # Make the request @@ -1290,4 +1291,47 @@ def get_users_followers( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetUsersFollowersResponse.model_validate(response_data) + return GetFollowersResponse.model_validate(response_data) + + + def get_by_username( + self, + username: str, + ) -> GetByUsernameResponse: + """ + Get User by username + Retrieves details of a specific User by their username. + Args: + username: A username. + Returns: + GetByUsernameResponse: Response data + """ + url = self.client.base_url + "/2/users/by/username/{username}" + if self.client.bearer_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.bearer_token}" + ) + elif self.client.access_token: + self.client.session.headers["Authorization"] = ( + f"Bearer {self.client.access_token}" + ) + # Ensure we have a valid access token + if self.client.oauth2_auth and self.client.token: + # Check if token needs refresh + if self.client.is_token_expired(): + self.client.refresh_token() + params = {} + url = url.replace("{username}", str(username)) + headers = {} + # Make the request + response = self.client.session.get( + url, + params=params, + headers=headers, + ) + # Check for errors + response.raise_for_status() + # Parse the response data + response_data = response.json() + # Convert to Pydantic model if applicable + return GetByUsernameResponse.model_validate(response_data) diff --git a/xdk/python/xdk/users/models.py b/xdk/python/xdk/users/models.py index 3cc9b3f4..bc1fcc95 100644 --- a/xdk/python/xdk/users/models.py +++ b/xdk/python/xdk/users/models.py @@ -1,7 +1,7 @@ """ -Users models for the X API. +users models for the X API. -This module provides models for the Users endpoints of the X API. +This module provides models for the users endpoints of the X API. """ from typing import Dict, List, Optional, Any, Union, Literal @@ -9,22 +9,22 @@ from datetime import datetime -# Models for getListsFollowers +# Models for get_followed_lists -class GetListsFollowersResponse(BaseModel): - """Response model for getListsFollowers""" +class GetFollowedListsResponse(BaseModel): + """Response model for get_followed_lists""" data: Optional[List] = None errors: Optional[List] = None - includes: Optional["GetListsFollowersResponseIncludes"] = None - meta: Optional["GetListsFollowersResponseMeta"] = None + includes: Optional["GetFollowedListsResponseIncludes"] = None + meta: Optional["GetFollowedListsResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetListsFollowersResponseIncludes(BaseModel): - """Nested model for GetListsFollowersResponseIncludes""" +class GetFollowedListsResponseIncludes(BaseModel): + """Nested model for GetFollowedListsResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -36,8 +36,8 @@ class GetListsFollowersResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetListsFollowersResponseMeta(BaseModel): - """Nested model for GetListsFollowersResponseMeta""" +class GetFollowedListsResponseMeta(BaseModel): + """Nested model for GetFollowedListsResponseMeta""" next_token: Optional[str] = None previous_token: Optional[str] = None @@ -46,22 +46,22 @@ class GetListsFollowersResponseMeta(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for getUsersMuting +# Models for get_list_memberships -class GetUsersMutingResponse(BaseModel): - """Response model for getUsersMuting""" +class GetListMembershipsResponse(BaseModel): + """Response model for get_list_memberships""" data: Optional[List] = None errors: Optional[List] = None - includes: Optional["GetUsersMutingResponseIncludes"] = None - meta: Optional["GetUsersMutingResponseMeta"] = None + includes: Optional["GetListMembershipsResponseIncludes"] = None + meta: Optional["GetListMembershipsResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersMutingResponseIncludes(BaseModel): - """Nested model for GetUsersMutingResponseIncludes""" +class GetListMembershipsResponseIncludes(BaseModel): + """Nested model for GetListMembershipsResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -73,8 +73,8 @@ class GetUsersMutingResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetUsersMutingResponseMeta(BaseModel): - """Nested model for GetUsersMutingResponseMeta""" +class GetListMembershipsResponseMeta(BaseModel): + """Nested model for GetListMembershipsResponseMeta""" next_token: Optional[str] = None previous_token: Optional[str] = None @@ -83,140 +83,135 @@ class GetUsersMutingResponseMeta(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for muteUser +# Models for get_reposts_of_me -class MuteUserRequest(BaseModel): - """Request model for muteUser""" +class GetRepostsOfMeResponse(BaseModel): + """Response model for get_reposts_of_me""" - target_user_id: Optional[str] = None + data: Optional[List] = None + errors: Optional[List] = None + includes: Optional["GetRepostsOfMeResponseIncludes"] = None + meta: Optional["GetRepostsOfMeResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class MuteUserResponse(BaseModel): - """Response model for muteUser""" +class GetRepostsOfMeResponseIncludes(BaseModel): + """Nested model for GetRepostsOfMeResponseIncludes""" - data: Optional["MuteUserResponseData"] = None - errors: Optional[List] = None + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class MuteUserResponseData(BaseModel): - """Nested model for MuteUserResponseData""" +class GetRepostsOfMeResponseMeta(BaseModel): + """Nested model for GetRepostsOfMeResponseMeta""" - muting: Optional[bool] = None + next_token: Optional[str] = None + previous_token: Optional[str] = None + result_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -# Models for getMyUser +# Models for get_owned_lists -class GetMyUserResponse(BaseModel): - """Response model for getMyUser""" +class GetOwnedListsResponse(BaseModel): + """Response model for get_owned_lists""" - data: Optional["GetMyUserResponseData"] = Field( - description="The X User object.", default_factory=dict - ) + data: Optional[List] = None errors: Optional[List] = None - includes: Optional["GetMyUserResponseIncludes"] = None + includes: Optional["GetOwnedListsResponseIncludes"] = None + meta: Optional["GetOwnedListsResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetMyUserResponseData(BaseModel): - """Nested model for GetMyUserResponseData""" +class GetOwnedListsResponseIncludes(BaseModel): + """Nested model for GetOwnedListsResponseIncludes""" - affiliation: Optional["GetMyUserResponseDataAffiliation"] = None - connection_status: Optional[List] = None - created_at: Optional[str] = None - description: Optional[str] = None - entities: Optional["GetMyUserResponseDataEntities"] = None - id: Optional[str] = None - location: Optional[str] = None - most_recent_tweet_id: Optional[str] = None - name: Optional[str] = None - pinned_tweet_id: Optional[str] = None - profile_banner_url: Optional[str] = None - profile_image_url: Optional[str] = None - protected: Optional[bool] = None - public_metrics: Optional["GetMyUserResponseDataPublicMetrics"] = None - receives_your_dm: Optional[bool] = None - subscription_type: Optional[str] = None - url: Optional[str] = None - username: Optional[str] = None - verified: Optional[bool] = None - verified_type: Optional[str] = None - withheld: Optional["GetMyUserResponseDataWithheld"] = None + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class GetMyUserResponseDataAffiliation(BaseModel): - """Nested model for GetMyUserResponseDataAffiliation""" +class GetOwnedListsResponseMeta(BaseModel): + """Nested model for GetOwnedListsResponseMeta""" - badge_url: Optional[str] = None - description: Optional[str] = None - url: Optional[str] = None - user_id: Optional[List] = None + next_token: Optional[str] = None + previous_token: Optional[str] = None + result_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class GetMyUserResponseDataEntities(BaseModel): - """Nested model for GetMyUserResponseDataEntities""" - - description: Optional["GetMyUserResponseDataEntitiesDescription"] = None - url: Optional["GetMyUserResponseDataEntitiesUrl"] = None - - model_config = ConfigDict(populate_by_name=True) +# Models for get_posts -class GetMyUserResponseDataEntitiesDescription(BaseModel): - """Nested model for GetMyUserResponseDataEntitiesDescription""" +class GetPostsResponse(BaseModel): + """Response model for get_posts""" - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None + data: Optional[List] = None + errors: Optional[List] = None + includes: Optional["GetPostsResponseIncludes"] = None + meta: Optional["GetPostsResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetMyUserResponseDataEntitiesUrl(BaseModel): - """Nested model for GetMyUserResponseDataEntitiesUrl""" +class GetPostsResponseIncludes(BaseModel): + """Nested model for GetPostsResponseIncludes""" - urls: Optional[List] = None + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class GetMyUserResponseDataPublicMetrics(BaseModel): - """Nested model for GetMyUserResponseDataPublicMetrics""" +class GetPostsResponseMeta(BaseModel): + """Nested model for GetPostsResponseMeta""" - followers_count: Optional[int] = None - following_count: Optional[int] = None - like_count: Optional[int] = None - listed_count: Optional[int] = None - tweet_count: Optional[int] = None + newest_id: Optional[str] = None + next_token: Optional[str] = None + oldest_id: Optional[str] = None + previous_token: Optional[str] = None + result_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class GetMyUserResponseDataWithheld(BaseModel): - """Nested model for GetMyUserResponseDataWithheld""" +# Models for get_liked_posts - country_codes: Optional[List] = None - scope: Optional[str] = None + +class GetLikedPostsResponse(BaseModel): + """Response model for get_liked_posts""" + + data: Optional[List] = None + errors: Optional[List] = None + includes: Optional["GetLikedPostsResponseIncludes"] = None + meta: Optional["GetLikedPostsResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetMyUserResponseIncludes(BaseModel): - """Nested model for GetMyUserResponseIncludes""" +class GetLikedPostsResponseIncludes(BaseModel): + """Nested model for GetLikedPostsResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -228,22 +223,32 @@ class GetMyUserResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for getUsersRepostsOfMe +class GetLikedPostsResponseMeta(BaseModel): + """Nested model for GetLikedPostsResponseMeta""" + + next_token: Optional[str] = None + previous_token: Optional[str] = None + result_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) -class GetUsersRepostsOfMeResponse(BaseModel): - """Response model for getUsersRepostsOfMe""" +# Models for get_timeline + + +class GetTimelineResponse(BaseModel): + """Response model for get_timeline""" data: Optional[List] = None errors: Optional[List] = None - includes: Optional["GetUsersRepostsOfMeResponseIncludes"] = None - meta: Optional["GetUsersRepostsOfMeResponseMeta"] = None + includes: Optional["GetTimelineResponseIncludes"] = None + meta: Optional["GetTimelineResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersRepostsOfMeResponseIncludes(BaseModel): - """Nested model for GetUsersRepostsOfMeResponseIncludes""" +class GetTimelineResponseIncludes(BaseModel): + """Nested model for GetTimelineResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -255,32 +260,33 @@ class GetUsersRepostsOfMeResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetUsersRepostsOfMeResponseMeta(BaseModel): - """Nested model for GetUsersRepostsOfMeResponseMeta""" +class GetTimelineResponseMeta(BaseModel): + """Nested model for GetTimelineResponseMeta""" + newest_id: Optional[str] = None next_token: Optional[str] = None + oldest_id: Optional[str] = None previous_token: Optional[str] = None result_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -# Models for searchUsers +# Models for get_by_usernames -class SearchUsersResponse(BaseModel): - """Response model for searchUsers""" +class GetByUsernamesResponse(BaseModel): + """Response model for get_by_usernames""" data: Optional[List] = None errors: Optional[List] = None - includes: Optional["SearchUsersResponseIncludes"] = None - meta: Optional["SearchUsersResponseMeta"] = None + includes: Optional["GetByUsernamesResponseIncludes"] = None model_config = ConfigDict(populate_by_name=True) -class SearchUsersResponseIncludes(BaseModel): - """Nested model for SearchUsersResponseIncludes""" +class GetByUsernamesResponseIncludes(BaseModel): + """Nested model for GetByUsernamesResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -292,30 +298,61 @@ class SearchUsersResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -class SearchUsersResponseMeta(BaseModel): - """Nested model for SearchUsersResponseMeta""" +# Models for get_mentions + + +class GetMentionsResponse(BaseModel): + """Response model for get_mentions""" + + data: Optional[List] = None + errors: Optional[List] = None + includes: Optional["GetMentionsResponseIncludes"] = None + meta: Optional["GetMentionsResponseMeta"] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetMentionsResponseIncludes(BaseModel): + """Nested model for GetMentionsResponseIncludes""" + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetMentionsResponseMeta(BaseModel): + """Nested model for GetMentionsResponseMeta""" + + newest_id: Optional[str] = None next_token: Optional[str] = None + oldest_id: Optional[str] = None previous_token: Optional[str] = None + result_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -# Models for getUsersByIds +# Models for search -class GetUsersByIdsResponse(BaseModel): - """Response model for getUsersByIds""" +class SearchResponse(BaseModel): + """Response model for search""" data: Optional[List] = None errors: Optional[List] = None - includes: Optional["GetUsersByIdsResponseIncludes"] = None + includes: Optional["SearchResponseIncludes"] = None + meta: Optional["SearchResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersByIdsResponseIncludes(BaseModel): - """Nested model for GetUsersByIdsResponseIncludes""" +class SearchResponseIncludes(BaseModel): + """Nested model for SearchResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -327,22 +364,31 @@ class GetUsersByIdsResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for getUsersBlocking +class SearchResponseMeta(BaseModel): + """Nested model for SearchResponseMeta""" + next_token: Optional[str] = None + previous_token: Optional[str] = None -class GetUsersBlockingResponse(BaseModel): - """Response model for getUsersBlocking""" + model_config = ConfigDict(populate_by_name=True) + + +# Models for get_muting + + +class GetMutingResponse(BaseModel): + """Response model for get_muting""" data: Optional[List] = None errors: Optional[List] = None - includes: Optional["GetUsersBlockingResponseIncludes"] = None - meta: Optional["GetUsersBlockingResponseMeta"] = None + includes: Optional["GetMutingResponseIncludes"] = None + meta: Optional["GetMutingResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersBlockingResponseIncludes(BaseModel): - """Nested model for GetUsersBlockingResponseIncludes""" +class GetMutingResponseIncludes(BaseModel): + """Nested model for GetMutingResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -354,8 +400,8 @@ class GetUsersBlockingResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetUsersBlockingResponseMeta(BaseModel): - """Nested model for GetUsersBlockingResponseMeta""" +class GetMutingResponseMeta(BaseModel): + """Nested model for GetMutingResponseMeta""" next_token: Optional[str] = None previous_token: Optional[str] = None @@ -364,132 +410,126 @@ class GetUsersBlockingResponseMeta(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for blockUsersDms +# Models for mute_user + + +class MuteUserRequest(BaseModel): + """Request model for mute_user""" + + target_user_id: Optional[str] = None + + model_config = ConfigDict(populate_by_name=True) -class BlockUsersDmsResponse(BaseModel): - """Response model for blockUsersDms""" +class MuteUserResponse(BaseModel): + """Response model for mute_user""" - data: Optional["BlockUsersDmsResponseData"] = None + data: Optional["MuteUserResponseData"] = None errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class BlockUsersDmsResponseData(BaseModel): - """Nested model for BlockUsersDmsResponseData""" +class MuteUserResponseData(BaseModel): + """Nested model for MuteUserResponseData""" - blocked: Optional[bool] = None + muting: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -# Models for getUsersByUsername +# Models for unblock_dms -class GetUsersByUsernameResponse(BaseModel): - """Response model for getUsersByUsername""" +class UnblockDmsResponse(BaseModel): + """Response model for unblock_dms""" - data: Optional["GetUsersByUsernameResponseData"] = Field( - description="The X User object.", default_factory=dict - ) + data: Optional["UnblockDmsResponseData"] = None errors: Optional[List] = None - includes: Optional["GetUsersByUsernameResponseIncludes"] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersByUsernameResponseData(BaseModel): - """Nested model for GetUsersByUsernameResponseData""" +class UnblockDmsResponseData(BaseModel): + """Nested model for UnblockDmsResponseData""" - affiliation: Optional["GetUsersByUsernameResponseDataAffiliation"] = None - connection_status: Optional[List] = None - created_at: Optional[str] = None - description: Optional[str] = None - entities: Optional["GetUsersByUsernameResponseDataEntities"] = None - id: Optional[str] = None - location: Optional[str] = None - most_recent_tweet_id: Optional[str] = None - name: Optional[str] = None - pinned_tweet_id: Optional[str] = None - profile_banner_url: Optional[str] = None - profile_image_url: Optional[str] = None - protected: Optional[bool] = None - public_metrics: Optional["GetUsersByUsernameResponseDataPublicMetrics"] = None - receives_your_dm: Optional[bool] = None - subscription_type: Optional[str] = None - url: Optional[str] = None - username: Optional[str] = None - verified: Optional[bool] = None - verified_type: Optional[str] = None - withheld: Optional["GetUsersByUsernameResponseDataWithheld"] = None + blocked: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersByUsernameResponseDataAffiliation(BaseModel): - """Nested model for GetUsersByUsernameResponseDataAffiliation""" +# Models for unmute_user - badge_url: Optional[str] = None - description: Optional[str] = None - url: Optional[str] = None - user_id: Optional[List] = None + +class UnmuteUserResponse(BaseModel): + """Response model for unmute_user""" + + data: Optional["UnmuteUserResponseData"] = None + errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersByUsernameResponseDataEntities(BaseModel): - """Nested model for GetUsersByUsernameResponseDataEntities""" +class UnmuteUserResponseData(BaseModel): + """Nested model for UnmuteUserResponseData""" - description: Optional["GetUsersByUsernameResponseDataEntitiesDescription"] = None - url: Optional["GetUsersByUsernameResponseDataEntitiesUrl"] = None + muting: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersByUsernameResponseDataEntitiesDescription(BaseModel): - """Nested model for GetUsersByUsernameResponseDataEntitiesDescription""" +# Models for get_bookmarks - annotations: Optional[List] = None - cashtags: Optional[List] = None - hashtags: Optional[List] = None - mentions: Optional[List] = None - urls: Optional[List] = None + +class GetBookmarksResponse(BaseModel): + """Response model for get_bookmarks""" + + data: Optional[List] = None + errors: Optional[List] = None + includes: Optional["GetBookmarksResponseIncludes"] = None + meta: Optional["GetBookmarksResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersByUsernameResponseDataEntitiesUrl(BaseModel): - """Nested model for GetUsersByUsernameResponseDataEntitiesUrl""" +class GetBookmarksResponseIncludes(BaseModel): + """Nested model for GetBookmarksResponseIncludes""" - urls: Optional[List] = None + media: Optional[List] = None + places: Optional[List] = None + polls: Optional[List] = None + topics: Optional[List] = None + tweets: Optional[List] = None + users: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersByUsernameResponseDataPublicMetrics(BaseModel): - """Nested model for GetUsersByUsernameResponseDataPublicMetrics""" +class GetBookmarksResponseMeta(BaseModel): + """Nested model for GetBookmarksResponseMeta""" - followers_count: Optional[int] = None - following_count: Optional[int] = None - like_count: Optional[int] = None - listed_count: Optional[int] = None - tweet_count: Optional[int] = None + next_token: Optional[str] = None + previous_token: Optional[str] = None + result_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersByUsernameResponseDataWithheld(BaseModel): - """Nested model for GetUsersByUsernameResponseDataWithheld""" +# Models for get_by_ids - country_codes: Optional[List] = None - scope: Optional[str] = None + +class GetByIdsResponse(BaseModel): + """Response model for get_by_ids""" + + data: Optional[List] = None + errors: Optional[List] = None + includes: Optional["GetByIdsResponseIncludes"] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersByUsernameResponseIncludes(BaseModel): - """Nested model for GetUsersByUsernameResponseIncludes""" +class GetByIdsResponseIncludes(BaseModel): + """Nested model for GetByIdsResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -501,22 +541,22 @@ class GetUsersByUsernameResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for getUsersFollowing +# Models for get_following -class GetUsersFollowingResponse(BaseModel): - """Response model for getUsersFollowing""" +class GetFollowingResponse(BaseModel): + """Response model for get_following""" data: Optional[List] = None errors: Optional[List] = None - includes: Optional["GetUsersFollowingResponseIncludes"] = None - meta: Optional["GetUsersFollowingResponseMeta"] = None + includes: Optional["GetFollowingResponseIncludes"] = None + meta: Optional["GetFollowingResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersFollowingResponseIncludes(BaseModel): - """Nested model for GetUsersFollowingResponseIncludes""" +class GetFollowingResponseIncludes(BaseModel): + """Nested model for GetFollowingResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -528,8 +568,8 @@ class GetUsersFollowingResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetUsersFollowingResponseMeta(BaseModel): - """Nested model for GetUsersFollowingResponseMeta""" +class GetFollowingResponseMeta(BaseModel): + """Nested model for GetFollowingResponseMeta""" next_token: Optional[str] = None previous_token: Optional[str] = None @@ -538,11 +578,11 @@ class GetUsersFollowingResponseMeta(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for followUser +# Models for follow_user class FollowUserRequest(BaseModel): - """Request model for followUser""" + """Request model for follow_user""" target_user_id: Optional[str] = None @@ -550,7 +590,7 @@ class FollowUserRequest(BaseModel): class FollowUserResponse(BaseModel): - """Response model for followUser""" + """Response model for follow_user""" data: Optional["FollowUserResponseData"] = None errors: Optional[List] = None @@ -567,119 +607,112 @@ class FollowUserResponseData(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for unmuteUser - - -class UnmuteUserResponse(BaseModel): - """Response model for unmuteUser""" - - data: Optional["UnmuteUserResponseData"] = None - errors: Optional[List] = None - - model_config = ConfigDict(populate_by_name=True) - - -class UnmuteUserResponseData(BaseModel): - """Nested model for UnmuteUserResponseData""" +# Models for get_me - muting: Optional[bool] = None - model_config = ConfigDict(populate_by_name=True) +class GetMeResponse(BaseModel): + """Response model for get_me""" - -# Models for unblockUsersDms - - -class UnblockUsersDmsResponse(BaseModel): - """Response model for unblockUsersDms""" - - data: Optional["UnblockUsersDmsResponseData"] = None + data: Optional["GetMeResponseData"] = Field( + description="The X User object.", default_factory=dict + ) errors: Optional[List] = None + includes: Optional["GetMeResponseIncludes"] = None model_config = ConfigDict(populate_by_name=True) -class UnblockUsersDmsResponseData(BaseModel): - """Nested model for UnblockUsersDmsResponseData""" +class GetMeResponseData(BaseModel): + """Nested model for GetMeResponseData""" - blocked: Optional[bool] = None + affiliation: Optional["GetMeResponseDataAffiliation"] = None + connection_status: Optional[List] = None + created_at: Optional[str] = None + description: Optional[str] = None + entities: Optional["GetMeResponseDataEntities"] = None + id: Optional[str] = None + location: Optional[str] = None + most_recent_tweet_id: Optional[str] = None + name: Optional[str] = None + pinned_tweet_id: Optional[str] = None + profile_banner_url: Optional[str] = None + profile_image_url: Optional[str] = None + protected: Optional[bool] = None + public_metrics: Optional["GetMeResponseDataPublicMetrics"] = None + receives_your_dm: Optional[bool] = None + subscription_type: Optional[str] = None + url: Optional[str] = None + username: Optional[str] = None + verified: Optional[bool] = None + verified_type: Optional[str] = None + withheld: Optional["GetMeResponseDataWithheld"] = None model_config = ConfigDict(populate_by_name=True) -# Models for unfollowUser - +class GetMeResponseDataAffiliation(BaseModel): + """Nested model for GetMeResponseDataAffiliation""" -class UnfollowUserResponse(BaseModel): - """Response model for unfollowUser""" - - data: Optional["UnfollowUserResponseData"] = None - errors: Optional[List] = None + badge_url: Optional[str] = None + description: Optional[str] = None + url: Optional[str] = None + user_id: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class UnfollowUserResponseData(BaseModel): - """Nested model for UnfollowUserResponseData""" +class GetMeResponseDataEntities(BaseModel): + """Nested model for GetMeResponseDataEntities""" - following: Optional[bool] = None + description: Optional["GetMeResponseDataEntitiesDescription"] = None + url: Optional["GetMeResponseDataEntitiesUrl"] = None model_config = ConfigDict(populate_by_name=True) -# Models for getListsMembers - - -class GetListsMembersResponse(BaseModel): - """Response model for getListsMembers""" +class GetMeResponseDataEntitiesDescription(BaseModel): + """Nested model for GetMeResponseDataEntitiesDescription""" - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetListsMembersResponseIncludes"] = None - meta: Optional["GetListsMembersResponseMeta"] = None + annotations: Optional[List] = None + cashtags: Optional[List] = None + hashtags: Optional[List] = None + mentions: Optional[List] = None + urls: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class GetListsMembersResponseIncludes(BaseModel): - """Nested model for GetListsMembersResponseIncludes""" +class GetMeResponseDataEntitiesUrl(BaseModel): + """Nested model for GetMeResponseDataEntitiesUrl""" - media: Optional[List] = None - places: Optional[List] = None - polls: Optional[List] = None - topics: Optional[List] = None - tweets: Optional[List] = None - users: Optional[List] = None + urls: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class GetListsMembersResponseMeta(BaseModel): - """Nested model for GetListsMembersResponseMeta""" +class GetMeResponseDataPublicMetrics(BaseModel): + """Nested model for GetMeResponseDataPublicMetrics""" - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None + followers_count: Optional[int] = None + following_count: Optional[int] = None + like_count: Optional[int] = None + listed_count: Optional[int] = None + tweet_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -# Models for getPostsRepostedBy +class GetMeResponseDataWithheld(BaseModel): + """Nested model for GetMeResponseDataWithheld""" - -class GetPostsRepostedByResponse(BaseModel): - """Response model for getPostsRepostedBy""" - - data: Optional[List] = None - errors: Optional[List] = None - includes: Optional["GetPostsRepostedByResponseIncludes"] = None - meta: Optional["GetPostsRepostedByResponseMeta"] = None + country_codes: Optional[List] = None + scope: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class GetPostsRepostedByResponseIncludes(BaseModel): - """Nested model for GetPostsRepostedByResponseIncludes""" +class GetMeResponseIncludes(BaseModel): + """Nested model for GetMeResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -691,39 +724,29 @@ class GetPostsRepostedByResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetPostsRepostedByResponseMeta(BaseModel): - """Nested model for GetPostsRepostedByResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) - - -# Models for getUsersById +# Models for get_by_id -class GetUsersByIdResponse(BaseModel): - """Response model for getUsersById""" +class GetByIdResponse(BaseModel): + """Response model for get_by_id""" - data: Optional["GetUsersByIdResponseData"] = Field( + data: Optional["GetByIdResponseData"] = Field( description="The X User object.", default_factory=dict ) errors: Optional[List] = None - includes: Optional["GetUsersByIdResponseIncludes"] = None + includes: Optional["GetByIdResponseIncludes"] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersByIdResponseData(BaseModel): - """Nested model for GetUsersByIdResponseData""" +class GetByIdResponseData(BaseModel): + """Nested model for GetByIdResponseData""" - affiliation: Optional["GetUsersByIdResponseDataAffiliation"] = None + affiliation: Optional["GetByIdResponseDataAffiliation"] = None connection_status: Optional[List] = None created_at: Optional[str] = None description: Optional[str] = None - entities: Optional["GetUsersByIdResponseDataEntities"] = None + entities: Optional["GetByIdResponseDataEntities"] = None id: Optional[str] = None location: Optional[str] = None most_recent_tweet_id: Optional[str] = None @@ -732,20 +755,20 @@ class GetUsersByIdResponseData(BaseModel): profile_banner_url: Optional[str] = None profile_image_url: Optional[str] = None protected: Optional[bool] = None - public_metrics: Optional["GetUsersByIdResponseDataPublicMetrics"] = None + public_metrics: Optional["GetByIdResponseDataPublicMetrics"] = None receives_your_dm: Optional[bool] = None subscription_type: Optional[str] = None url: Optional[str] = None username: Optional[str] = None verified: Optional[bool] = None verified_type: Optional[str] = None - withheld: Optional["GetUsersByIdResponseDataWithheld"] = None + withheld: Optional["GetByIdResponseDataWithheld"] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersByIdResponseDataAffiliation(BaseModel): - """Nested model for GetUsersByIdResponseDataAffiliation""" +class GetByIdResponseDataAffiliation(BaseModel): + """Nested model for GetByIdResponseDataAffiliation""" badge_url: Optional[str] = None description: Optional[str] = None @@ -755,17 +778,17 @@ class GetUsersByIdResponseDataAffiliation(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetUsersByIdResponseDataEntities(BaseModel): - """Nested model for GetUsersByIdResponseDataEntities""" +class GetByIdResponseDataEntities(BaseModel): + """Nested model for GetByIdResponseDataEntities""" - description: Optional["GetUsersByIdResponseDataEntitiesDescription"] = None - url: Optional["GetUsersByIdResponseDataEntitiesUrl"] = None + description: Optional["GetByIdResponseDataEntitiesDescription"] = None + url: Optional["GetByIdResponseDataEntitiesUrl"] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersByIdResponseDataEntitiesDescription(BaseModel): - """Nested model for GetUsersByIdResponseDataEntitiesDescription""" +class GetByIdResponseDataEntitiesDescription(BaseModel): + """Nested model for GetByIdResponseDataEntitiesDescription""" annotations: Optional[List] = None cashtags: Optional[List] = None @@ -776,16 +799,16 @@ class GetUsersByIdResponseDataEntitiesDescription(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetUsersByIdResponseDataEntitiesUrl(BaseModel): - """Nested model for GetUsersByIdResponseDataEntitiesUrl""" +class GetByIdResponseDataEntitiesUrl(BaseModel): + """Nested model for GetByIdResponseDataEntitiesUrl""" urls: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersByIdResponseDataPublicMetrics(BaseModel): - """Nested model for GetUsersByIdResponseDataPublicMetrics""" +class GetByIdResponseDataPublicMetrics(BaseModel): + """Nested model for GetByIdResponseDataPublicMetrics""" followers_count: Optional[int] = None following_count: Optional[int] = None @@ -796,8 +819,8 @@ class GetUsersByIdResponseDataPublicMetrics(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetUsersByIdResponseDataWithheld(BaseModel): - """Nested model for GetUsersByIdResponseDataWithheld""" +class GetByIdResponseDataWithheld(BaseModel): + """Nested model for GetByIdResponseDataWithheld""" country_codes: Optional[List] = None scope: Optional[str] = None @@ -805,8 +828,8 @@ class GetUsersByIdResponseDataWithheld(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetUsersByIdResponseIncludes(BaseModel): - """Nested model for GetUsersByIdResponseIncludes""" +class GetByIdResponseIncludes(BaseModel): + """Nested model for GetByIdResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -818,21 +841,22 @@ class GetUsersByIdResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for getUsersByUsernames +# Models for get_blocking -class GetUsersByUsernamesResponse(BaseModel): - """Response model for getUsersByUsernames""" +class GetBlockingResponse(BaseModel): + """Response model for get_blocking""" data: Optional[List] = None errors: Optional[List] = None - includes: Optional["GetUsersByUsernamesResponseIncludes"] = None + includes: Optional["GetBlockingResponseIncludes"] = None + meta: Optional["GetBlockingResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersByUsernamesResponseIncludes(BaseModel): - """Nested model for GetUsersByUsernamesResponseIncludes""" +class GetBlockingResponseIncludes(BaseModel): + """Nested model for GetBlockingResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -844,22 +868,72 @@ class GetUsersByUsernamesResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for getPostsLikingUsers +class GetBlockingResponseMeta(BaseModel): + """Nested model for GetBlockingResponseMeta""" + + next_token: Optional[str] = None + previous_token: Optional[str] = None + result_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for block_dms + + +class BlockDmsResponse(BaseModel): + """Response model for block_dms""" + + data: Optional["BlockDmsResponseData"] = None + errors: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class BlockDmsResponseData(BaseModel): + """Nested model for BlockDmsResponseData""" + + blocked: Optional[bool] = None + + model_config = ConfigDict(populate_by_name=True) -class GetPostsLikingUsersResponse(BaseModel): - """Response model for getPostsLikingUsers""" +# Models for unfollow_user + + +class UnfollowUserResponse(BaseModel): + """Response model for unfollow_user""" + + data: Optional["UnfollowUserResponseData"] = None + errors: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class UnfollowUserResponseData(BaseModel): + """Nested model for UnfollowUserResponseData""" + + following: Optional[bool] = None + + model_config = ConfigDict(populate_by_name=True) + + +# Models for get_followers + + +class GetFollowersResponse(BaseModel): + """Response model for get_followers""" data: Optional[List] = None errors: Optional[List] = None - includes: Optional["GetPostsLikingUsersResponseIncludes"] = None - meta: Optional["GetPostsLikingUsersResponseMeta"] = None + includes: Optional["GetFollowersResponseIncludes"] = None + meta: Optional["GetFollowersResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetPostsLikingUsersResponseIncludes(BaseModel): - """Nested model for GetPostsLikingUsersResponseIncludes""" +class GetFollowersResponseIncludes(BaseModel): + """Nested model for GetFollowersResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -871,8 +945,8 @@ class GetPostsLikingUsersResponseIncludes(BaseModel): model_config = ConfigDict(populate_by_name=True) -class GetPostsLikingUsersResponseMeta(BaseModel): - """Nested model for GetPostsLikingUsersResponseMeta""" +class GetFollowersResponseMeta(BaseModel): + """Nested model for GetFollowersResponseMeta""" next_token: Optional[str] = None previous_token: Optional[str] = None @@ -881,22 +955,112 @@ class GetPostsLikingUsersResponseMeta(BaseModel): model_config = ConfigDict(populate_by_name=True) -# Models for getUsersFollowers +# Models for get_by_username -class GetUsersFollowersResponse(BaseModel): - """Response model for getUsersFollowers""" +class GetByUsernameResponse(BaseModel): + """Response model for get_by_username""" - data: Optional[List] = None + data: Optional["GetByUsernameResponseData"] = Field( + description="The X User object.", default_factory=dict + ) errors: Optional[List] = None - includes: Optional["GetUsersFollowersResponseIncludes"] = None - meta: Optional["GetUsersFollowersResponseMeta"] = None + includes: Optional["GetByUsernameResponseIncludes"] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByUsernameResponseData(BaseModel): + """Nested model for GetByUsernameResponseData""" + + affiliation: Optional["GetByUsernameResponseDataAffiliation"] = None + connection_status: Optional[List] = None + created_at: Optional[str] = None + description: Optional[str] = None + entities: Optional["GetByUsernameResponseDataEntities"] = None + id: Optional[str] = None + location: Optional[str] = None + most_recent_tweet_id: Optional[str] = None + name: Optional[str] = None + pinned_tweet_id: Optional[str] = None + profile_banner_url: Optional[str] = None + profile_image_url: Optional[str] = None + protected: Optional[bool] = None + public_metrics: Optional["GetByUsernameResponseDataPublicMetrics"] = None + receives_your_dm: Optional[bool] = None + subscription_type: Optional[str] = None + url: Optional[str] = None + username: Optional[str] = None + verified: Optional[bool] = None + verified_type: Optional[str] = None + withheld: Optional["GetByUsernameResponseDataWithheld"] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByUsernameResponseDataAffiliation(BaseModel): + """Nested model for GetByUsernameResponseDataAffiliation""" + + badge_url: Optional[str] = None + description: Optional[str] = None + url: Optional[str] = None + user_id: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByUsernameResponseDataEntities(BaseModel): + """Nested model for GetByUsernameResponseDataEntities""" + + description: Optional["GetByUsernameResponseDataEntitiesDescription"] = None + url: Optional["GetByUsernameResponseDataEntitiesUrl"] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByUsernameResponseDataEntitiesDescription(BaseModel): + """Nested model for GetByUsernameResponseDataEntitiesDescription""" + + annotations: Optional[List] = None + cashtags: Optional[List] = None + hashtags: Optional[List] = None + mentions: Optional[List] = None + urls: Optional[List] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByUsernameResponseDataEntitiesUrl(BaseModel): + """Nested model for GetByUsernameResponseDataEntitiesUrl""" + + urls: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class GetUsersFollowersResponseIncludes(BaseModel): - """Nested model for GetUsersFollowersResponseIncludes""" +class GetByUsernameResponseDataPublicMetrics(BaseModel): + """Nested model for GetByUsernameResponseDataPublicMetrics""" + + followers_count: Optional[int] = None + following_count: Optional[int] = None + like_count: Optional[int] = None + listed_count: Optional[int] = None + tweet_count: Optional[int] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByUsernameResponseDataWithheld(BaseModel): + """Nested model for GetByUsernameResponseDataWithheld""" + + country_codes: Optional[List] = None + scope: Optional[str] = None + + model_config = ConfigDict(populate_by_name=True) + + +class GetByUsernameResponseIncludes(BaseModel): + """Nested model for GetByUsernameResponseIncludes""" media: Optional[List] = None places: Optional[List] = None @@ -906,13 +1070,3 @@ class GetUsersFollowersResponseIncludes(BaseModel): users: Optional[List] = None model_config = ConfigDict(populate_by_name=True) - - -class GetUsersFollowersResponseMeta(BaseModel): - """Nested model for GetUsersFollowersResponseMeta""" - - next_token: Optional[str] = None - previous_token: Optional[str] = None - result_count: Optional[int] = None - - model_config = ConfigDict(populate_by_name=True) diff --git a/xdk/python/xdk/webhooks/__init__.py b/xdk/python/xdk/webhooks/__init__.py index cce446f5..41a2d821 100644 --- a/xdk/python/xdk/webhooks/__init__.py +++ b/xdk/python/xdk/webhooks/__init__.py @@ -1,7 +1,7 @@ """ -Webhooks module for the X API. +webhooks module for the X API. -This module provides access to the Webhooks endpoints of the X API. +This module provides access to the webhooks endpoints of the X API. """ from .client import WebhooksClient diff --git a/xdk/python/xdk/webhooks/client.py b/xdk/python/xdk/webhooks/client.py index a614a677..4cd3fd8f 100644 --- a/xdk/python/xdk/webhooks/client.py +++ b/xdk/python/xdk/webhooks/client.py @@ -1,7 +1,7 @@ """ -Webhooks client for the X API. +webhooks client for the X API. -This module provides a client for interacting with the Webhooks endpoints of the X API. +This module provides a client for interacting with the webhooks endpoints of the X API. """ from __future__ import annotations @@ -12,35 +12,32 @@ if TYPE_CHECKING: from ..client import Client from .models import ( - ValidateWebhooksResponse, - DeleteWebhooksResponse, - GetWebhooksResponse, - CreateWebhooksRequest, - CreateWebhooksResponse, + GetResponse, + CreateRequest, + CreateResponse, + ValidateResponse, + DeleteResponse, ) class WebhooksClient: - """Client for Webhooks operations""" + """Client for webhooks operations""" def __init__(self, client: Client): self.client = client - def validate_webhooks( + def get( self, - webhook_id: str, - ) -> ValidateWebhooksResponse: + ) -> GetResponse: """ - Validate webhook - Triggers a CRC check for a given webhook. - Args: - webhook_id: The ID of the webhook to check. + Get webhook + Get a list of webhook configs associated with a client app. Returns: - ValidateWebhooksResponse: Response data + GetResponse: Response data """ - url = self.client.base_url + "/2/webhooks/{webhook_id}" + url = self.client.base_url + "/2/webhooks" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -50,10 +47,9 @@ def validate_webhooks( f"Bearer {self.client.access_token}" ) params = {} - url = url.replace("{webhook_id}", str(webhook_id)) headers = {} # Make the request - response = self.client.session.put( + response = self.client.session.get( url, params=params, headers=headers, @@ -63,22 +59,21 @@ def validate_webhooks( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return ValidateWebhooksResponse.model_validate(response_data) + return GetResponse.model_validate(response_data) - def delete_webhooks( + def create( self, - webhook_id: str, - ) -> DeleteWebhooksResponse: + body: Optional[CreateRequest] = None, + ) -> CreateResponse: """ - Delete webhook - Deletes an existing webhook configuration. - Args: - webhook_id: The ID of the webhook to delete. + Create webhook + Creates a new webhook configuration. + body: Request body Returns: - DeleteWebhooksResponse: Response data + CreateResponse: Response data """ - url = self.client.base_url + "/2/webhooks/{webhook_id}" + url = self.client.base_url + "/2/webhooks" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -88,35 +83,36 @@ def delete_webhooks( f"Bearer {self.client.access_token}" ) params = {} - url = url.replace("{webhook_id}", str(webhook_id)) headers = {} + headers["Content-Type"] = "application/json" # Make the request - response = self.client.session.delete( + response = self.client.session.post( url, params=params, headers=headers, + json=body.model_dump(exclude_none=True) if body else None, ) # Check for errors response.raise_for_status() # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return DeleteWebhooksResponse.model_validate(response_data) + return CreateResponse.model_validate(response_data) - def get_webhooks( + def validate( self, - webhook_config_fields: List = None, - ) -> GetWebhooksResponse: + webhook_id: Any, + ) -> ValidateResponse: """ - Get webhook - Get a list of webhook configs associated with a client app. + Validate webhook + Triggers a CRC check for a given webhook. Args: - webhook_config_fields: A comma separated list of WebhookConfig fields to display. + webhook_id: The ID of the webhook to check. Returns: - GetWebhooksResponse: Response data + ValidateResponse: Response data """ - url = self.client.base_url + "/2/webhooks" + url = self.client.base_url + "/2/webhooks/{webhook_id}" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -126,13 +122,10 @@ def get_webhooks( f"Bearer {self.client.access_token}" ) params = {} - if webhook_config_fields is not None: - params["webhook_config.fields"] = ",".join( - str(item) for item in webhook_config_fields - ) + url = url.replace("{webhook_id}", str(webhook_id)) headers = {} # Make the request - response = self.client.session.get( + response = self.client.session.put( url, params=params, headers=headers, @@ -142,21 +135,22 @@ def get_webhooks( # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return GetWebhooksResponse.model_validate(response_data) + return ValidateResponse.model_validate(response_data) - def create_webhooks( + def delete( self, - body: Optional[CreateWebhooksRequest] = None, - ) -> CreateWebhooksResponse: + webhook_id: Any, + ) -> DeleteResponse: """ - Create webhook - Creates a new webhook configuration. - body: Request body + Delete webhook + Deletes an existing webhook configuration. + Args: + webhook_id: The ID of the webhook to delete. Returns: - CreateWebhooksResponse: Response data + DeleteResponse: Response data """ - url = self.client.base_url + "/2/webhooks" + url = self.client.base_url + "/2/webhooks/{webhook_id}" if self.client.bearer_token: self.client.session.headers["Authorization"] = ( f"Bearer {self.client.bearer_token}" @@ -166,18 +160,17 @@ def create_webhooks( f"Bearer {self.client.access_token}" ) params = {} + url = url.replace("{webhook_id}", str(webhook_id)) headers = {} - headers["Content-Type"] = "application/json" # Make the request - response = self.client.session.post( + response = self.client.session.delete( url, params=params, headers=headers, - json=body.model_dump(exclude_none=True) if body else None, ) # Check for errors response.raise_for_status() # Parse the response data response_data = response.json() # Convert to Pydantic model if applicable - return CreateWebhooksResponse.model_validate(response_data) + return DeleteResponse.model_validate(response_data) diff --git a/xdk/python/xdk/webhooks/models.py b/xdk/python/xdk/webhooks/models.py index 854bc315..2c9a487e 100644 --- a/xdk/python/xdk/webhooks/models.py +++ b/xdk/python/xdk/webhooks/models.py @@ -1,7 +1,7 @@ """ -Webhooks models for the X API. +webhooks models for the X API. -This module provides models for the Webhooks endpoints of the X API. +This module provides models for the webhooks endpoints of the X API. """ from typing import Dict, List, Optional, Any, Union, Literal @@ -9,84 +9,84 @@ from datetime import datetime -# Models for validateWebhooks +# Models for get -class ValidateWebhooksResponse(BaseModel): - """Response model for validateWebhooks""" +class GetResponse(BaseModel): + """Response model for get""" - data: Optional["ValidateWebhooksResponseData"] = None + data: Optional[List] = None errors: Optional[List] = None + meta: Optional["GetResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class ValidateWebhooksResponseData(BaseModel): - """Nested model for ValidateWebhooksResponseData""" +class GetResponseMeta(BaseModel): + """Nested model for GetResponseMeta""" - attempted: Optional[bool] = None + result_count: Optional[int] = None model_config = ConfigDict(populate_by_name=True) -# Models for deleteWebhooks +# Models for create -class DeleteWebhooksResponse(BaseModel): - """Response model for deleteWebhooks""" +class CreateRequest(BaseModel): + """Request model for create""" - data: Optional["DeleteWebhooksResponseData"] = None - errors: Optional[List] = None + url: Optional[str] = None model_config = ConfigDict(populate_by_name=True) -class DeleteWebhooksResponseData(BaseModel): - """Nested model for DeleteWebhooksResponseData""" +class CreateResponse(BaseModel): + """Response model for create""" - deleted: Optional[bool] = None + created_at: Optional[str] = None + id: Optional[str] = None + url: Optional[str] = None + valid: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -# Models for getWebhooks +# Models for validate -class GetWebhooksResponse(BaseModel): - """Response model for getWebhooks""" +class ValidateResponse(BaseModel): + """Response model for validate""" - data: Optional[List] = None + data: Optional["ValidateResponseData"] = None errors: Optional[List] = None - meta: Optional["GetWebhooksResponseMeta"] = None model_config = ConfigDict(populate_by_name=True) -class GetWebhooksResponseMeta(BaseModel): - """Nested model for GetWebhooksResponseMeta""" +class ValidateResponseData(BaseModel): + """Nested model for ValidateResponseData""" - result_count: Optional[int] = None + attempted: Optional[bool] = None model_config = ConfigDict(populate_by_name=True) -# Models for createWebhooks +# Models for delete -class CreateWebhooksRequest(BaseModel): - """Request model for createWebhooks""" +class DeleteResponse(BaseModel): + """Response model for delete""" - url: Optional[str] = None + data: Optional["DeleteResponseData"] = None + errors: Optional[List] = None model_config = ConfigDict(populate_by_name=True) -class CreateWebhooksResponse(BaseModel): - """Response model for createWebhooks""" +class DeleteResponseData(BaseModel): + """Nested model for DeleteResponseData""" - created_at: Optional[str] = None - id: Optional[str] = None - url: Optional[str] = None - valid: Optional[bool] = None + deleted: Optional[bool] = None model_config = ConfigDict(populate_by_name=True)