diff --git a/xdk-gen/src/python/generator.rs b/xdk-gen/src/python/generator.rs
index c47f361b..457a08ce 100644
--- a/xdk-gen/src/python/generator.rs
+++ b/xdk-gen/src/python/generator.rs
@@ -49,7 +49,12 @@ language! {
render "paginator" => "xdk/paginator.py",
render "init_py" => "xdk/__init__.py",
render "pyproject_toml" => "pyproject.toml",
- render "readme" => "README.md"
+ render "sphinx_conf" => "conf.py",
+ render "generate_docs_simple" => "scripts/generate-docs-simple.py",
+ render "process_for_mintlify" => "scripts/process-for-mintlify.py",
+ render "watch_docs" => "scripts/watch-docs.py",
+ render "readme" => "README.md",
+ render "gitignore" => ".gitignore"
],
tests: [
multiple {
diff --git a/xdk-gen/src/typescript/generator.rs b/xdk-gen/src/typescript/generator.rs
index 02c2704e..013536e0 100644
--- a/xdk-gen/src/typescript/generator.rs
+++ b/xdk-gen/src/typescript/generator.rs
@@ -85,7 +85,11 @@ language! {
render "tsup.config" => "tsup.config.ts",
render "typedoc.json" => "typedoc.json",
render "npmignore" => ".npmignore",
+ render "gitignore" => ".gitignore",
render "generate_docs" => "scripts/generate-docs.js",
+ render "generate_docs_simple" => "scripts/generate-docs-simple.js",
+ render "watch_docs" => "scripts/watch-docs.js",
+ render "process_for_mintlify" => "scripts/process-for-mintlify.js",
render "readme" => "README.md"
],
tests: [
diff --git a/xdk-gen/templates/python/generate_docs_simple.j2 b/xdk-gen/templates/python/generate_docs_simple.j2
new file mode 100644
index 00000000..6caf934a
--- /dev/null
+++ b/xdk-gen/templates/python/generate_docs_simple.j2
@@ -0,0 +1,151 @@
+#!/usr/bin/env python3
+"""
+AUTO-GENERATED FILE - DO NOT EDIT
+This file was automatically generated by the XDK build tool.
+Any manual changes will be overwritten on the next generation.
+
+Generate API documentation for the Python SDK using Sphinx with markdown output.
+"""
+
+import os
+import sys
+import shutil
+import subprocess
+from pathlib import Path
+
+print('🚀 Generating X API SDK Documentation...')
+
+# Try to use virtual environment if available
+venv_python = Path('.venv') / 'bin' / 'python'
+if venv_python.exists():
+ print('📦 Using virtual environment...')
+ python_exe = str(venv_python)
+else:
+ python_exe = sys.executable
+
+# Configuration
+DOCS_DIR = Path('docs')
+SPHINX_SOURCE_DIR = Path('docs_source')
+SPHINX_BUILD_DIR = DOCS_DIR / '_build'
+SPHINX_MARKDOWN_DIR = DOCS_DIR
+
+# Clean up old docs
+if DOCS_DIR.exists():
+ shutil.rmtree(DOCS_DIR)
+DOCS_DIR.mkdir(parents=True, exist_ok=True)
+
+# Clean up old source
+if SPHINX_SOURCE_DIR.exists():
+ shutil.rmtree(SPHINX_SOURCE_DIR)
+
+# Create Sphinx source directory structure
+SPHINX_SOURCE_DIR.mkdir(parents=True, exist_ok=True)
+(SPHINX_SOURCE_DIR / '_static').mkdir(exist_ok=True)
+(SPHINX_SOURCE_DIR / '_templates').mkdir(exist_ok=True)
+
+# Copy conf.py from root (should be generated)
+conf_py_path = Path('conf.py')
+if conf_py_path.exists():
+ shutil.copy(conf_py_path, SPHINX_SOURCE_DIR / 'conf.py')
+else:
+ print('⚠️ Warning: conf.py not found. Sphinx may not work correctly.')
+
+try:
+ # Use sphinx-apidoc to auto-generate API documentation
+ print('📚 Running sphinx-apidoc to generate API documentation structure...')
+ apidoc_cmd = [
+ python_exe, '-m', 'sphinx.ext.apidoc',
+ '-o', str(SPHINX_SOURCE_DIR),
+ '-f', # Force overwrite
+ '--separate', # Put each module in its own file
+ 'xdk', # Source package
+ ]
+
+ subprocess.run(apidoc_cmd, check=True, capture_output=True, text=True)
+
+ # Create or update index.rst
+ index_content = """X API SDK Documentation
+==========================
+
+Welcome to the X API SDK documentation.
+
+.. toctree::
+ :maxdepth: 2
+ :caption: API Reference:
+
+ modules
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+"""
+
+ (SPHINX_SOURCE_DIR / 'index.rst').write_text(index_content)
+
+ # Run Sphinx with markdown builder
+ print('📚 Running Sphinx to generate markdown documentation...')
+
+ sphinx_cmd = [
+ python_exe, '-m', 'sphinx',
+ '-b', 'markdown', # Use markdown builder
+ str(SPHINX_SOURCE_DIR),
+ str(SPHINX_MARKDOWN_DIR),
+ ]
+
+ result = subprocess.run(sphinx_cmd, check=True, capture_output=True, text=True)
+ print('✅ Documentation generated successfully in docs/')
+
+ # Clean up build directory
+ if SPHINX_BUILD_DIR.exists():
+ shutil.rmtree(SPHINX_BUILD_DIR)
+
+ # Clean up source directory
+ if SPHINX_SOURCE_DIR.exists():
+ shutil.rmtree(SPHINX_SOURCE_DIR)
+
+except subprocess.CalledProcessError as e:
+ print(f'❌ Documentation generation failed: {e}')
+ if e.stdout:
+ print(f'stdout: {e.stdout}')
+ if e.stderr:
+ print(f'stderr: {e.stderr}')
+ sys.exit(1)
+except FileNotFoundError:
+ print('❌ Sphinx not found.')
+ print('💡 Installing dependencies...')
+ try:
+ # Try to install using uv if available
+ if shutil.which('uv'):
+ subprocess.run(['uv', 'pip', 'install', '-e', '.[dev]'], check=True, shell=False)
+ else:
+ # Fallback to pip
+ subprocess.run([sys.executable, '-m', 'pip', 'install', 'sphinx', 'myst-parser', 'sphinx-markdown-builder'], check=True)
+ print('✅ Dependencies installed. Please run the script again.')
+ except subprocess.CalledProcessError:
+ print('❌ Failed to install dependencies automatically.')
+ print('💡 Please install manually with:')
+ print(" uv pip install -e '.[dev]'")
+ print(' or')
+ print(' pip install sphinx myst-parser sphinx-markdown-builder')
+ sys.exit(1)
+except ImportError as e:
+ if 'myst_parser' in str(e) or 'myst-parser' in str(e):
+ print('❌ myst-parser not found.')
+ print('💡 Installing dependencies...')
+ try:
+ if shutil.which('uv'):
+ subprocess.run(['uv', 'pip', 'install', '-e', '.[dev]'], check=True, shell=False)
+ else:
+ subprocess.run([sys.executable, '-m', 'pip', 'install', 'myst-parser', 'sphinx-markdown-builder'], check=True)
+ print('✅ Dependencies installed. Please run the script again.')
+ except subprocess.CalledProcessError:
+ print('❌ Failed to install dependencies automatically.')
+ print('💡 Please install manually with:')
+ print(" uv pip install -e '.[dev]'")
+ else:
+ raise
+ sys.exit(1)
+
diff --git a/xdk-gen/templates/python/gitignore.j2 b/xdk-gen/templates/python/gitignore.j2
new file mode 100644
index 00000000..33b25094
--- /dev/null
+++ b/xdk-gen/templates/python/gitignore.j2
@@ -0,0 +1,44 @@
+# Documentation generation outputs
+# These are generated by the docs scripts and should not be committed
+
+# Sphinx output directories
+docs/
+docs/_build/
+docs_source/
+
+# Mintlify processed documentation
+mintlify-docs/
+
+# Python cache
+__pycache__/
+*.py[cod]
+*$py.class
+*.so
+.Python
+
+# Virtual environments
+venv/
+env/
+ENV/
+.venv
+
+# IDE
+.vscode/
+.idea/
+*.swp
+*.swo
+
+# Distribution / packaging
+dist/
+build/
+*.egg-info/
+
+# Testing
+.pytest_cache/
+.coverage
+htmlcov/
+
+# Type checking
+.mypy_cache/
+.pytype/
+
diff --git a/xdk-gen/templates/python/process_for_mintlify.j2 b/xdk-gen/templates/python/process_for_mintlify.j2
new file mode 100644
index 00000000..ba970b76
--- /dev/null
+++ b/xdk-gen/templates/python/process_for_mintlify.j2
@@ -0,0 +1,1585 @@
+#!/usr/bin/env python3
+"""
+AUTO-GENERATED FILE - DO NOT EDIT
+This file was automatically generated by the XDK build tool.
+Any manual changes will be overwritten on the next generation.
+
+Process Sphinx-generated markdown documentation for Mintlify.
+"""
+
+import os
+import sys
+import json
+import re
+import shutil
+from pathlib import Path
+from typing import Dict, List, Optional, Set
+
+print('🚀 Processing X API SDK Documentation for Mintlify...')
+
+# Mintlify configuration
+MINTLIFY_CONFIG = {
+ 'outputDir': 'mintlify-docs',
+ 'baseUrl': 'https://docs.x.com',
+ 'title': 'X API SDK v{{ version }}',
+ 'description': 'Python SDK for the X API with comprehensive pagination, authentication, and streaming support.',
+ 'version': '{{ version }}',
+ 'githubUrl': 'https://github.com/xdevplatform/xdk',
+}
+
+def clean_title(title: str, file_path: str = '', content: str = '') -> str:
+ """Clean and improve title formatting."""
+ if not isinstance(title, str):
+ title = str(title)
+
+ # Try to extract class name from content first (more reliable)
+ if content:
+ # Look for class definition: ### *class* xdk.module.ClassName
+ class_match = re.search(
+ r'\*class\*\s+[^\s]*\.([A-Z][a-zA-Z0-9_]*Client|Client|Paginator|OAuth2PKCEAuth)\b',
+ content
+ )
+ if class_match:
+ return class_match.group(1)
+
+ # Remove module suffix
+ title = re.sub(r'\s+module\s*$', '', title, flags=re.IGNORECASE)
+
+ # Extract class name from patterns like "xdk.users.client.UsersClient"
+ class_match = re.search(r'\.([A-Z][a-zA-Z0-9_]+Client|Paginator|OAuth2PKCEAuth)\b', title)
+ if class_match:
+ return class_match.group(1)
+ # Fallback to generic Client only if no specific client found
+ if 'Client' in title and not re.search(r'[A-Z][a-zA-Z0-9_]+Client', title):
+ class_match = re.search(r'\.(Client)\b', title)
+ if class_match:
+ return class_match.group(1)
+
+ # Extract class name from patterns like "*class* xdk.users.client.UsersClient"
+ class_match2 = re.search(r'\*class\*\s+[^\s]*\.([A-Z][a-zA-Z0-9_]*Client|Client|Paginator|OAuth2PKCEAuth)\b', title)
+ if class_match2:
+ return class_match2.group(1)
+
+ # Remove xdk. prefix
+ title = re.sub(r'^xdk\.', '', title)
+
+ # Convert snake_case to PascalCase for module names
+ if '.' in title and not title[0].isupper():
+ parts = title.split('.')
+ # Capitalize each part
+ title = '.'.join(p.capitalize() for p in parts)
+
+ # Clean up
+ title = (
+ re.sub(r'<.*?>', '', title) # Remove generic type parameters
+ .replace('Class: ', '')
+ .replace('Interface: ', '')
+ .replace('*class*', '')
+ .replace('*', '')
+ .replace('\\', '')
+ .replace('\n', ' ')
+ .strip()
+ )
+
+ return title
+
+def generate_frontmatter(title: str, sidebar_title: Optional[str] = None, file_path: str = '') -> str:
+ """Generate Mintlify frontmatter."""
+ cleaned_title = clean_title(title, file_path)
+ cleaned_sidebar = clean_title(sidebar_title, file_path) if sidebar_title else cleaned_title
+
+ frontmatter = f'title: "{cleaned_title}"\n'
+ if sidebar_title:
+ frontmatter += f'sidebarTitle: "{cleaned_sidebar}"\n'
+
+ return f'---\n{frontmatter}---\n\n'
+
+def reorganize_class_structure(content: str, file_path: str) -> str:
+ """Reorganize content into proper sections like TypeScript."""
+ # Check if this is a class/client file
+ if 'client' not in file_path.lower() and 'models' not in file_path.lower():
+ return content
+
+ # Find class definition - handle both formats
+ # Pattern 1: ### *class* xdk.module.ClassName(params)
+ # Pattern 2: ### `*class* xdk.module.ClassName`(params)
+ class_match = re.search(r'###\s+(?:`?)?\*class\*\s+([^\n(]+)(?:`?)?\s*\(([^)]*)\)', content)
+ if not class_match:
+ return content
+
+ class_name_full = class_match.group(1).strip().replace('*', '').replace('`', '')
+ # Extract just the class name (last part after last dot)
+ class_name = class_name_full.split('.')[-1] if '.' in class_name_full else class_name_full
+ class_params = class_match.group(2).strip()
+
+ # Extract description after class definition
+ class_start = class_match.end()
+ next_section = content.find('###', class_start)
+ if next_section == -1:
+ next_section = len(content)
+
+ description = content[class_start:next_section].strip()
+ # Extract "Bases:" line for later use as Badge
+ bases_match = re.search(r'Bases:\s*`([^`]+)`', description, re.IGNORECASE)
+ bases = bases_match.group(1).strip() if bases_match else None
+ # Remove "Bases:" line - we'll add it as a Badge
+ description = re.sub(r'Bases:\s*`[^`]+`\s*\n?', '', description, flags=re.IGNORECASE)
+ # Remove any stray closing parentheses
+ description = re.sub(r'^\)\s*\n?', '', description)
+ description = description.strip()
+
+ # Find all methods and properties
+ methods = []
+ constructors = []
+ properties = []
+
+ # Pattern for methods: ### method_name(params) → ReturnType
+ method_pattern = r'###\s+`?([^\n(]+)`?\s*\(([^)]*)\)(?:\s*→\s*([^\n]+))?'
+ for match in re.finditer(method_pattern, content):
+ method_name = match.group(1).strip().replace('`', '').replace('\\', '').replace('*', '')
+ params = match.group(2).strip()
+ return_type = match.group(3).strip() if match.group(3) else None
+
+ # Find method body
+ method_start = match.start()
+ next_method = content.find('###', method_start + 1)
+ if next_method == -1:
+ method_body = content[method_start:]
+ else:
+ method_body = content[method_start:next_method]
+
+ method_info = {
+ 'name': method_name,
+ 'params': params,
+ 'return_type': return_type,
+ 'body': method_body
+ }
+
+ if method_name == '__init__' or 'constructor' in method_name.lower():
+ constructors.append(method_info)
+ elif method_name.startswith('property') or 'property' in method_body.lower():
+ properties.append(method_info)
+ else:
+ methods.append(method_info)
+
+ # Rebuild content with proper sections
+ sections = []
+
+ # Class definition and description
+ sections.append(f'## {class_name}\n\n')
+ sections.append('Class\n')
+ if bases:
+ sections.append(f'\nBases: {bases}\n')
+ if description:
+ sections.append(f'\n{description}\n')
+
+ # Constructors section
+ if constructors:
+ sections.append('\n## Constructors\n')
+ for const in constructors:
+ sections.append(const['body'])
+
+ # Methods section
+ if methods:
+ sections.append('\n## Methods\n')
+ for method in methods:
+ sections.append(method['body'])
+
+ # Properties section
+ if properties:
+ sections.append('\n## Properties\n')
+ for prop in properties:
+ sections.append(prop['body'])
+
+ # If we found methods/constructors, rebuild content
+ if constructors or methods or properties:
+ before_class = content[:class_match.start()]
+ # Get remaining content after last method
+ if methods:
+ last_method_end = content.rfind(methods[-1]['body'])
+ remaining = content[last_method_end + len(methods[-1]['body']):]
+ elif constructors:
+ last_constructor_end = content.rfind(constructors[-1]['body'])
+ remaining = content[last_constructor_end + len(constructors[-1]['body']):]
+ else:
+ remaining = content[next_section:]
+
+ # Clean up any stray characters and duplicate class definitions
+ remaining = re.sub(r'^\)\s*\n', '', remaining)
+ # Remove duplicate class definitions that might have been left behind
+ # Pattern: ### `class xdk.module.ClassName` followed by description and parameters
+ # Match the full duplicate class definition block
+ remaining = re.sub(
+ r'###\s+`?class\s+xdk\.[^\n]+\n\n[^\n]+\n\n(?:####\s+Parameters[^\n]+\n\n]+>\s*\s*\n)?',
+ '',
+ remaining
+ )
+ # Also remove any standalone class definitions without parameters
+ remaining = re.sub(
+ r'###\s+`?\*?class\*?\s+xdk\.[^\n]+\n\n[^\n]+\n\n',
+ '',
+ remaining
+ )
+ # Remove any remaining class definition patterns (more aggressive)
+ remaining = re.sub(
+ r'###\s+`?class\s+[^\n]+\n\n[^\n]+\n\n(?:####\s+Parameters[^\n]+\n\n)?',
+ '',
+ remaining
+ )
+
+ return before_class + '\n'.join(sections) + remaining
+
+ return content
+
+def clean_class_definitions(content: str) -> str:
+ """Clean up class definition headers."""
+ # Remove any remaining class definition headers that weren't processed
+ # Pattern: ### `*class* xdk.module.ClassName`(params) or ## xdk.module.ClassName
+ # These should already be converted by reorganize_class_structure, but clean up any leftovers
+
+ # Remove any stray class definition patterns
+ content = re.sub(
+ r'##\s+xdk\.[^\n]+\n\n\)\s*\n',
+ '',
+ content
+ )
+
+ # Clean up any remaining "Bases:" lines that weren't converted
+ content = re.sub(r'^Bases:\s*`[^`]+`\s*\n?', '', content, flags=re.MULTILINE)
+
+ return content
+
+def fix_method_names(content: str) -> str:
+ """Fix method names with escaped underscores."""
+ # Pattern: ### ``\_\_init_\_`` -> ### `__init__`
+ # Handle double backticks with escaped underscores
+ content = re.sub(r'###\s+``\\?(_+[^`]+_+)``', r'### `\1`', content)
+
+ # Pattern: ### ``method\_name`` -> ### `method_name`
+ content = re.sub(r'###\s+``([^`]*)\\?(_[^`]*)``', r'### `\1\2`', content)
+
+ # Pattern: ### ``\_\_init_\_``(params) -> ### `__init__`(params)
+ content = re.sub(r'###\s+``([^`]*)\\?(_[^`]*)``\s*\(', r'### `\1\2`(', content)
+
+ # Remove any remaining escaped underscores in method names (single backticks)
+ content = re.sub(r'###\s+`([^`]*)\\?(_[^`]*)`\s*\(', r'### `\1\2`(', content)
+
+ # Fix any remaining escaped underscores in code blocks
+ content = re.sub(r'`([^`]*)\\?(_[^`]*)`', r'`\1\2`', content)
+
+ return content
+
+def improve_method_formatting(content: str) -> str:
+ """Improve method formatting to match TypeScript style with ParamField components."""
+ # Pattern: ### method_name(params) → ReturnType
+ def convert_method(match):
+ method_header = match.group(0)
+ method_name = match.group(1).strip().replace('*', '').replace('`', '').replace('\\', '').replace('_', '_')
+ params_str = match.group(2).strip() if match.group(2) else ''
+ return_type = match.group(3).strip() if match.group(3) else None
+
+ # Find method body (until next ### or ####)
+ method_start = match.start()
+ next_method = content.find('###', method_start + 1)
+ if next_method == -1:
+ method_body = content[method_start:]
+ else:
+ method_body = content[method_start:next_method]
+
+ # Extract description (text after method header, before :param)
+ desc_match = re.search(r'###[^\n]+\n\n([^\n]+(?:\n(?!:param|####|###|####)[^\n]+)*)', method_body, re.MULTILINE)
+ description = desc_match.group(1).strip() if desc_match else ''
+ # Remove method name from description if it appears
+ description = re.sub(r'^' + re.escape(method_name) + r'\s*$', '', description, flags=re.MULTILINE).strip()
+
+ # Parse parameters and convert to ParamField components
+ param_fields = []
+ if params_str:
+ # Simple parameter parsing (split by comma, but handle type annotations)
+ params = []
+ current = ''
+ depth = 0
+ for char in params_str:
+ if char in '[(':
+ depth += 1
+ elif char in '])':
+ depth -= 1
+ elif char == ',' and depth == 0:
+ if current.strip():
+ params.append(current.strip())
+ current = ''
+ continue
+ current += char
+ if current.strip():
+ params.append(current.strip())
+
+ for param in params:
+ # Parse: name: type = default
+ # Handle cases like: client: [Client](xdk.md#xdk.Client)
+ param_match = re.match(r'(\w+)(?:\s*:\s*([^=]+))?(?:\s*=\s*(.+))?$', param.strip())
+ if param_match:
+ param_name = param_match.group(1)
+ param_type_raw = param_match.group(2).strip() if param_match.group(2) else 'Any'
+ param_default = param_match.group(3).strip() if param_match.group(3) else None
+
+ # Clean type - handle markdown links first
+ # Pattern: [Type](path#anchor) -> extract just "Type"
+ link_match = re.search(r'\[([^\]]+)\]\(([^\)]+)\)', param_type_raw)
+ if link_match:
+ param_type = link_match.group(1) # Use just the link text
+ else:
+ # No link, use the raw type but clean it
+ param_type = param_type_raw
+ # Remove file references and anchors
+ param_type = re.sub(r'[a-z_]+\.(md|py)#[^\s]*', '', param_type)
+ param_type = re.sub(r'#[^\s]*', '', param_type)
+ # Remove incomplete link patterns like "Client]("
+ param_type = re.sub(r'\]\([^\)]*$', '', param_type)
+ param_type = re.sub(r'\]\([^\)]*\)', '', param_type)
+
+ # Clean up the type string
+ param_type = param_type.replace('|', ' or ').strip()
+ # Remove any trailing/leading brackets and parentheses
+ param_type = re.sub(r'^[\[\(]+', '', param_type)
+ param_type = re.sub(r'[\]\)]+$', '', param_type)
+ # Remove any remaining incomplete patterns
+ param_type = re.sub(r'\]\(.*$', '', param_type)
+ # Escape angle brackets for MDX
+ param_type = param_type.replace('<', '<').replace('>', '>')
+ # Clean up extra spaces
+ param_type = re.sub(r'\s+', ' ', param_type).strip()
+ # If type is empty or just brackets, default to Any
+ if not param_type or param_type in ['[', ']', '()', '(', ')', '](']:
+ param_type = 'Any'
+
+ # Find param description
+ param_desc_match = re.search(rf':param\s+{param_name}:\s*([^\n]+)', method_body)
+ param_desc = param_desc_match.group(1).strip() if param_desc_match else ''
+
+ # Build ParamField - use path instead of name
+ # For Python methods, parameters are function arguments
+ # Use "path" location for most parameters, or "body" if it's clearly a request body
+ param_location = 'body' if param_name.lower() in ['body', 'data', 'payload', 'request'] else 'path'
+ param_field = f'', '>')
+ param_field += f' default="{param_default_clean}"'
+ param_field += '>'
+ if param_desc:
+ param_field += f'\n{param_desc}\n'
+ param_field += ''
+ param_fields.append(param_field)
+
+ # Build new method format
+ new_method = f'### `{method_name}`\n\n'
+ if description:
+ new_method += f'{description}\n\n'
+
+ if param_fields:
+ new_method += '#### Parameters\n\n'
+ new_method += '\n\n'.join(param_fields) + '\n\n'
+
+ if return_type:
+ # Extract return description
+ return_desc_match = re.search(r':param\s+Returns?:\s*([^\n]+)', method_body)
+ return_desc = return_desc_match.group(1).strip() if return_desc_match else ''
+
+ # Clean return type - handle markdown links
+ return_type_clean = re.sub(r'\[([^\]]+)\]\([^\)]+\)', r'\1', return_type)
+ return_type_clean = re.sub(r'[a-z_]+\.(md|py)#[^\s]+', '', return_type_clean)
+ return_type_clean = return_type_clean.replace('[', '').replace(']', '')
+ return_type_clean = return_type_clean.replace('<', '<').replace('>', '>')
+ return_type_clean = re.sub(r':param\s+\w+:\s*', '', return_type_clean).strip()
+ return_type_clean = re.sub(r'\s+', ' ', return_type_clean).strip()
+
+ new_method += '#### Returns\n\n'
+ new_method += f'`{return_type_clean}`'
+ if return_desc and return_desc != return_type_clean:
+ new_method += f' - {return_desc}'
+ new_method += '\n\n'
+
+ return new_method
+
+ # Convert method signatures to use ParamField components
+ # Match: ### method_name(params) → ReturnType
+ def process_all_methods(text):
+ # Find all method definitions
+ method_pattern = r'###\s+`?([^\n(]+)`?\s*\(([^)]*)\)(?:\s*→\s*([^\n]+))?'
+ methods = list(re.finditer(method_pattern, text, re.MULTILINE))
+
+ if not methods:
+ return text
+
+ # Build result by processing each method and replacing its entire section
+ result_parts = []
+ last_pos = 0
+
+ for i, match in enumerate(methods):
+ # Add content before this method
+ result_parts.append(text[last_pos:match.start()])
+
+ # Find where this method's body ends (next method or end of content)
+ method_start = match.start()
+ if i + 1 < len(methods):
+ next_method_start = methods[i + 1].start()
+ else:
+ next_method_start = len(text)
+
+ # Get the full method section to replace
+ method_section = text[method_start:next_method_start]
+
+ # Convert this method
+ converted = convert_method(match)
+
+ # Remove the old method content from the section
+ result_parts.append(converted)
+
+ last_pos = next_method_start
+
+ # Add remaining content
+ result_parts.append(text[last_pos:])
+
+ return ''.join(result_parts)
+
+ content = process_all_methods(content)
+
+ # Clean up any remaining :param lines that weren't converted
+ content = re.sub(r':param\s+(\w+):\s*([^\n]+)', r'**`\1`** - \2', content)
+ content = re.sub(r':param\s+Returns?:\s*([^\n]+)', r'**Returns:** \1', content)
+
+ # Remove duplicate return descriptions
+ content = re.sub(
+ r'(#### Returns\n\n`[^\n]+`[^\n]+\n\n)(\*\*`[^\n]+\*\*[^\n]+\n)+',
+ r'\1',
+ content
+ )
+
+ # Remove duplicate method descriptions
+ content = re.sub(
+ r'(### `[^\n]+`\n\n[^\n]+\n\n[^\n]+\n\n)(\1)',
+ r'\1',
+ content
+ )
+
+ # Clean up any remaining old format parameter lines after ParamField sections
+ content = re.sub(
+ r'(\n\n)(\*\*`[^\n]+\*\*[^\n]+\n)+',
+ r'\1',
+ content
+ )
+
+ # Remove duplicate "Returns:" text in return sections
+ content = re.sub(
+ r'(#### Returns\n\n`[^\n]+`)\s*-\s*\*\*`[^\n]+\*\*\s*-\s*([^\n]+)',
+ r'\1 - \2',
+ content
+ )
+
+ # Remove duplicate class definitions that appear after the main class header
+ # Pattern: ### `class xdk.module.ClassName` followed by description and parameters
+ # Find the main class header (should be ## ClassName)
+ main_class_match = re.search(r'##\s+([A-Z][a-zA-Z0-9_]+Client|Client|Paginator|OAuth2PKCEAuth|BaseModel)', content)
+ if main_class_match:
+ # Everything after the main class header should not have duplicate class definitions
+ before_main = content[:main_class_match.end()]
+ after_main = content[main_class_match.end():]
+
+ # Remove any class definitions from after_main
+ after_main = re.sub(
+ r'###\s+`?class\s+xdk\.[^\n]+\n\n[^\n]+\n\n(?:####\s+Parameters[^\n]+\n\n]+>\s*\s*\n)?',
+ '',
+ after_main
+ )
+
+ content = before_main + after_main
+
+ # Remove duplicate parameter sections (#### Parameters appearing twice in a row)
+ content = re.sub(
+ r'(#### Parameters\n\n]+>\s*\s*\n)\1',
+ r'\1',
+ content
+ )
+
+ return content
+
+def process_markdown_content(content: str, title: str, current_file_path: str, known_targets: Dict[str, str]) -> str:
+ """Process and clean markdown content for Mintlify."""
+ # Remove Sphinx-specific elements
+ content = re.sub(r'\[\[include:.*?\]\]', '', content)
+
+ # Fix code block formatting
+ content = re.sub(r'```python\n', '```python\n', content)
+
+ # Remove Sphinx breadcrumbs
+ content = re.sub(r'^\[[^\]]+\]\([^\)]+\)\s*/\s*.*\n?', '', content, flags=re.MULTILINE)
+
+ # Remove auto-generated comments at the beginning
+ # Pattern: "Auto-generated ..." followed by description paragraphs ending with "Generated automatically - do not edit manually."
+ content = re.sub(
+ r'^Auto-generated[^\n]+\n\n[^\n]+\n\n[^\n]+\n\nAll methods[^\n]+\n\nGenerated automatically[^\n]+\n\n',
+ '',
+ content,
+ flags=re.MULTILINE
+ )
+ # Also remove variations - single line or multiple paragraphs
+ content = re.sub(
+ r'^Auto-generated[^\n]+\n\n',
+ '',
+ content,
+ flags=re.MULTILINE
+ )
+ content = re.sub(
+ r'^This module provides[^\n]+\n\n',
+ '',
+ content,
+ flags=re.MULTILINE
+ )
+ content = re.sub(
+ r'^All methods[^\n]+\n\n',
+ '',
+ content,
+ flags=re.MULTILINE
+ )
+ content = re.sub(
+ r'^Generated automatically[^\n]+\n\n',
+ '',
+ content,
+ flags=re.MULTILINE
+ )
+
+ # Fix method names first - remove escaped underscores (before other processing)
+ content = fix_method_names(content)
+
+ # Reorganize content into proper sections (Constructors, Methods, Properties)
+ content = reorganize_class_structure(content, current_file_path)
+
+ # Clean up class definitions - remove asterisks, format properly
+ content = clean_class_definitions(content)
+
+ # Improve method formatting - convert to better structure with ParamField
+ content = improve_method_formatting(content)
+
+ # Fix internal links to absolute Mintlify paths
+ def fix_link(match):
+ text = match.group(1)
+ raw_link_path = match.group(2)
+ hash_part = match.group(3) or ''
+
+ # Skip absolute URLs
+ if re.match(r'^(?:https?:|mailto:|tel:)', raw_link_path, re.I):
+ return match.group(0)
+
+ link_path = raw_link_path.replace('.md', '').replace('.rst', '')
+ current_dir = str(Path(current_file_path).parent) if current_file_path else ''
+
+ # Normalize path
+ if current_dir:
+ joined = Path(current_dir) / link_path
+ target_path = str(joined).replace('\\', '/').replace('docs/', '')
+ else:
+ target_path = link_path.replace('\\', '/').replace('docs/', '')
+
+ # Use known target if available
+ base_name = Path(target_path).stem
+ if base_name in known_targets and '/' not in target_path:
+ target_path = f"{known_targets[base_name]}/{base_name}"
+
+ return f'[{text}](/xdks/python/reference/{target_path}{hash_part})'
+
+ content = re.sub(
+ r'\[([^\]]+)\]\(([^)#]+?)(?:\.(?:md|rst))?(#[^)]+)?\)',
+ fix_link,
+ content
+ )
+
+ # Fix method signatures
+ content = re.sub(r'### (.*?)\(', r'### `\1`(', content)
+
+ # Add proper spacing
+ content = re.sub(r'\n\n\n+', '\n\n', content)
+
+ # Remove first H1 header (frontmatter title will be used)
+ content = re.sub(r'^\s*#\s+[^\n]+\n+', '', content)
+
+ # Escape generic type angle brackets (but preserve component tags)
+ # Simple approach: escape angle brackets, then fix Badge tags
+ content = re.sub(
+ r'\b([A-Z][A-Za-z0-9_]*)<([^>\n]+)>',
+ lambda m: f"{m.group(1)}<{m.group(2).replace('<', '<').replace('>', '>')}>",
+ content
+ )
+
+ # Fix any escaped Badge tags (they shouldn't have angle brackets anyway)
+ content = content.replace('</Badge>', '')
+ content = content.replace('Class</Badge>', 'Class')
+ content = content.replace('BaseModel</Badge>', 'BaseModel')
+
+ # Remove Table of Contents blocks
+ content = re.sub(r'(^##\s+Table of contents\n[\s\S]*?)(?=^##\s+|^#\s+|\Z)', '', content, flags=re.MULTILINE | re.IGNORECASE)
+
+ # Fix asterisks around type annotations that break MDX parsing
+ # Pattern: #### field *: Type* *= value* -> #### field : Type = value
+ # This handles cases like: model_config *: ClassVar[ConfigDict]* *= {'extra': 'allow', ...}*
+ # Match: field *: Type* *= value* (where value can contain quotes, commas, etc.)
+ # Use a more specific pattern that includes the header marker
+ content = re.sub(
+ r'(####\s+\w+)\s+\*\s*:\s*([^*]+?)\s*\*\s*\*\s*=\s*([^\n]+?)\s*\*',
+ r'\1: \2 = \3',
+ content,
+ flags=re.MULTILINE
+ )
+
+ # Fix asterisks around type annotations without equals (just type)
+ # Pattern: field *: Type* -> field : Type
+ content = re.sub(r'(\w+)\s+\*\s*:\s*([^*\n]+?)\s*\*', r'\1: \2', content, flags=re.MULTILINE)
+
+ # Fix remaining asterisks around equals signs (standalone)
+ # Pattern: *= value* -> = value
+ content = re.sub(r'\*\s*=\s*([^\n]+?)\s*\*', r'= \1', content, flags=re.MULTILINE)
+
+ # Fix asterisks around class/function names in headers
+ # Pattern: ### *class* name -> ### class name
+ content = re.sub(r'###\s+\*\s*(\w+)\s*\*\s+', r'### \1 ', content)
+
+ # Convert property headers with type annotations to Mintlify components
+ # This must happen AFTER asterisk removal
+ # Pattern: #### field: Type = value\n\nDescription
+ # Convert to: Description
+ def convert_property_header(match):
+ field_name = match.group(1)
+ type_and_default = match.group(2).strip()
+ description = match.group(3).strip() if match.group(3) else ''
+
+ # Split type and default value
+ # Format: ClassVar[ConfigDict] = {'extra': 'allow', ...}
+ type_match = re.match(r'([^=]+?)(?:\s*=\s*(.+))?$', type_and_default)
+ if type_match:
+ type_annotation = type_match.group(1).strip()
+ default_value = type_match.group(2).strip() if type_match.group(2) else None
+ else:
+ type_annotation = type_and_default
+ default_value = None
+
+ # Clean up type annotation - remove ClassVar, brackets, etc.
+ # ClassVar[ConfigDict] -> ConfigDict
+ type_clean = re.sub(r'ClassVar\[([^\]]+)\]', r'\1', type_annotation)
+ # Remove any remaining brackets for display
+ type_clean = type_clean.replace('[', '').replace(']', '').strip()
+
+ # Escape type for MDX
+ type_clean = type_clean.replace('<', '<').replace('>', '>')
+
+ # Build the component
+ component = f''
+
+ if description:
+ component += f'\n{description}\n'
+
+ component += ''
+ return component
+
+ # Match: #### field: Type = value\n\nDescription
+ # Match the entire header line, then blank line, then description
+ content = re.sub(
+ r'####\s+(\w+)\s*:\s*([^\n]+?)\s*\n\s*\n([^\n]+(?:\n(?!####)[^\n]+)*)?',
+ convert_property_header,
+ content,
+ flags=re.MULTILINE
+ )
+
+ return content
+
+def get_category_from_path(file_path: str) -> str:
+ """Determine category from file path."""
+ if 'client' in file_path.lower() and 'Client' in file_path:
+ return 'Getting Started'
+ if 'paginator' in file_path.lower():
+ return 'Core Features'
+ if 'stream' in file_path.lower():
+ return 'Core Features'
+ return 'API Reference'
+
+def process_docs():
+ """Main processing function."""
+ try:
+ # First, try to generate documentation
+ print('📚 Generating documentation...')
+ try:
+ import subprocess
+ result = subprocess.run(
+ [sys.executable, 'scripts/generate-docs-simple.py'],
+ check=True,
+ capture_output=True,
+ text=True
+ )
+ print(result.stdout)
+ except subprocess.CalledProcessError as e:
+ print('⚠️ Sphinx generation failed, using existing docs if available...')
+ if not Path('docs').exists() or not any(Path('docs').iterdir()):
+ raise RuntimeError(
+ 'No documentation found and Sphinx generation failed. '
+ 'Please install Sphinx: pip install sphinx myst-parser sphinx-markdown-builder'
+ )
+ print('✅ Using existing documentation files')
+
+ # Create output directory
+ output_dir = Path(MINTLIFY_CONFIG['outputDir'])
+ if output_dir.exists():
+ shutil.rmtree(output_dir)
+ output_dir.mkdir(parents=True, exist_ok=True)
+
+ # Create subdirectories
+ (output_dir / 'xdks' / 'python' / 'reference').mkdir(parents=True, exist_ok=True)
+
+ print('📝 Processing markdown files...')
+
+ # Get all markdown files
+ docs_dir = Path('docs')
+ files = list(docs_dir.rglob('*.md'))
+
+ # Build map of known targets
+ known_targets = {}
+ for f in files:
+ base = f.stem
+ parent = f.parent.name
+ if parent and parent != 'docs' and base not in known_targets:
+ known_targets[base] = parent
+
+ processed_files = []
+ navigation = {
+ 'Getting Started': [],
+ 'Core Features': [],
+ 'API Reference': [],
+ 'Authentication': [],
+ 'Utilities': []
+ }
+
+ for file_path in files:
+ if file_path.name == 'README.md':
+ continue
+
+ # Special handling for modules.md - convert to accordion format
+ if file_path.name == 'modules.md':
+ continue # Will process separately
+
+ content = file_path.read_text(encoding='utf-8')
+
+ # Extract title
+ title_match = re.search(r'^#\s+(.+)$', content, re.MULTILINE)
+ title = title_match.group(1) if title_match else file_path.stem
+
+ # Clean title using improved function (pass content for better extraction)
+ cleaned_title = clean_title(title, str(file_path), content)
+
+ category = get_category_from_path(str(file_path))
+ processed_content = process_markdown_content(
+ content, cleaned_title, str(file_path.relative_to(docs_dir)), known_targets
+ )
+
+ # Generate frontmatter
+ frontmatter = generate_frontmatter(cleaned_title, cleaned_title, str(file_path))
+ final_content = frontmatter + processed_content
+
+ # Determine output path
+ base_name = file_path.stem
+ sub_dir = file_path.parent.name if file_path.parent != docs_dir else ''
+ target_dir = output_dir / 'xdks' / 'python' / 'reference' / sub_dir
+ target_dir.mkdir(parents=True, exist_ok=True)
+ output_path = target_dir / f'{base_name}.mdx'
+
+ # Write processed file
+ output_path.write_text(final_content, encoding='utf-8')
+ processed_files.append({
+ 'title': cleaned_title,
+ 'category': category,
+ 'path': str(output_path),
+ 'originalPath': str(file_path)
+ })
+
+ # Add to navigation
+ if category in navigation:
+ relative_ref_path = f"{sub_dir}/{base_name}" if sub_dir else base_name
+ navigation[category].append({
+ 'title': cleaned_title,
+ 'url': f'xdks/python/reference/{relative_ref_path}'
+ })
+
+ # Create high-level documentation pages
+ print('📄 Creating high-level documentation pages...')
+
+ # Overview page
+ overview_content = '''---
+title: Python XDK
+sidebarTitle: Overview
+---
+
+The Python XDK (X Developer Kit) is our official client library for interacting with the X API v2 using Python. It allows developers to get started with our API quickly and build applications with it. It is generated based on our official [OpenAPI specification](https://api.x.com/2/openapi.json). It abstracts away low-level HTTP details while providing fine-grained control when needed.
+
+## Key Features
+
+- 🔐 **OAuth Support**: Full support for Bearer Token (app-only) auth, OAuth 2.0 with PKCE (user context), and OAuth 1.0.
+
+- 🔄 **Pagination**: Automatically page through large results. The XDK takes care of pagination without requiring you to make multiple API calls using the `next_token`.
+
+- 📡 **Streaming**: Supports real-time data streaming for endpoints like filtered stream that require persistent http connection.
+
+- 🎯 **Comprehensive Coverage**: Supports all X API v2 endpoints including such as search, timelines, filtered-stream and more.
+
+**Version Compatibility**: Python 3.8+. Tested on CPython and PyPy.
+
+**License**: [MIT License](https://github.com/xdevplatform/xdk/blob/main/LICENSE)
+'''
+
+ (output_dir / 'xdks' / 'python' / 'overview.mdx').write_text(overview_content)
+
+ # Install page
+ install_content = '''---
+title: "Install"
+sidebarTitle: "Install"
+---
+
+The XDK Python SDK is available directly from the GitHub repository and can be installed via `pip`.
+
+## Prerequisites
+
+- Python 3.8 or higher.
+
+- `pip` and `venv` for virtual environments (recommended).
+
+## Quick Install
+
+Install the XDK from the GitHub subdirectory:
+
+```bash
+pip install xdk
+```
+
+This fetches the latest generated version from the `main` branch.
+
+## Development Install
+
+For development or contributing:
+
+1. Clone the repository:
+
+ ```bash
+ git clone https://github.com/xdevplatform/xdk.git
+ cd xdk/python
+ ```
+
+2. Install dependencies in editable mode:
+
+ ```bash
+ pip install -e .
+ ```
+
+ This installs the SDK and its runtime dependencies.
+
+3. (Optional) Install dev dependencies for testing/linting:
+
+ ```bash
+ pip install -e .[dev]
+ ```
+
+## Verification
+
+Test the installation:
+
+```python
+import xdk
+print(xdk.__version__) # Should print the XDK version
+```
+
+**Note:** Since the XDK is generated using the OpenAPI spec, always check the [X API changelog](https://docs.x.com/changelog) and XDK release notes in the repo for any changes.
+'''
+
+ (output_dir / 'xdks' / 'python' / 'install.mdx').write_text(install_content)
+
+ # Quickstart page
+ quickstart_content = '''---
+title: Quickstart
+sidebarTitle: Quickstart
+---
+
+This example showcases how to quickly search for Posts using the XDK using Bearer Token authentication.
+
+## Step 1: Install the SDK
+
+```bash
+pip install xdk
+```
+
+## Step 2: Get Your Bearer Token
+
+1. Log in to the [X Developer Portal](https://developer.x.com/en/portal/dashboard).
+
+2. Create or select an app.
+
+3. Under "Keys and Tokens," generate a Bearer Token (app-only auth).
+
+## Step 3: Write and Run Your First Script
+
+Create a file `quickstart.py`:
+
+```python
+# Import the client
+from xdk import Client
+
+# Replace with your actual Bearer Token
+client = Client(bearer_token="YOUR_BEARER_TOKEN_HERE")
+
+# Fetch recent Posts mentioning "api"
+response = client.posts.search_recent(query="api", max_results=10)
+
+# Print the first Post's text
+if response.data:
+ print(f"Latest Post: {response.data[0]['text']}")
+else:
+ print("No Posts found.")
+```
+
+Run it:
+
+```bash
+python quickstart.py
+```
+
+**Expected Output**:
+
+```
+Latest Post: Exciting updates on XDK Python SDK!
+```
+
+**Troubleshooting**: If you get a 401 error, double-check your Bearer Token. For rate limits (429), wait and retry.
+
+## Next Steps
+
+- Explore [Authentication](/xdks/python/authentication) to understand how to use Bearer Token (app-only) auth, OAuth 2.0 with PKCE (user context), and OAuth 1.0.
+
+- Learn about [Pagination](/xdks/python/pagination) for use-cases where you want large number of results returned without worrying about making multiple API calls.
+
+- Dive into [Streaming](/xdks/python/streaming) to learn how to work with real-time data.
+'''
+
+ (output_dir / 'xdks' / 'python' / 'quickstart.mdx').write_text(quickstart_content)
+
+ # Authentication page
+ auth_content = '''---
+title: Authentication
+sidebarTitle: Authentication
+---
+
+The X API requires authentication for all endpoints. The XDK supports three authentication methods:
+
+1. Bearer Token (app-only)
+
+2. OAuth 2.0 with PKCE
+
+3. OAuth 1.0a User Context
+
+- **Bearer Token**: Use this for read-only access for endpoints that support app-auth (e.g., searching Post's, streaming endpoints).
+
+- **OAuth 2.0 PKCE**: Secure authentication for scope-based, user-authorized access (e.g. getting authenticated user's Post non_public metrics)
+
+- **OAuth 1.0a**: Legacy auth for full read/write access, including DMs and media uploads.
+
+**Note**: We recommend developers move away from OAuth 1.0 and use OAuth 2.0 for user-authorized access.
+
+Obtain credentials from the [X Developer Portal](https://developer.x.com/en/portal/dashboard). You'll need an approved developer account and an app with appropriate permissions (e.g., Read + Write).
+
+## Creating a Client
+
+All authentication flows create a `Client` instance:
+
+```python
+from xdk import Client
+```
+
+### 1. Bearer Token (App-Only)
+
+For read-only operations without user context.
+
+**Steps**:
+
+1. In the Developer Portal, generate a Bearer Token for your app.
+
+2. Pass it to the `Client`.
+
+**Example**:
+
+```python
+client = Client(bearer_token="XXXXX")
+```
+
+**Usage**:
+
+```python
+response = client.posts.search_recent(query="python", max_results=10)
+print(response.data[0]['text']) # Access first Post
+```
+
+### 2. OAuth 2.0 with PKCE (User Context)
+
+This example shows how to use OAuth 2.0 with Proof Key for Code Exchange (PKCE). Use this for user-specific access (e.g. posting on behalf of a user), uploading media for a user etc.).
+
+**Steps**:
+
+1. In the developer portal, register your app with a redirect URI (e.g., `http://localhost:8080/callback`).
+
+2. Get Client ID (no secret needed for PKCE).
+
+3. Initiate the flow, direct user to auth URL and handle callback.
+
+**Example** (using a web server for callback):
+
+```python
+from xdk.auth import OAuth2PKCE
+from urllib.parse import urlparse
+import webbrowser
+
+# Step 1: Create PKCE instance
+auth = OAuth2PKCE(
+ client_id="your_client_id",
+ redirect_uri="http://localhost:8080/callback",
+ scopes=["tweet.read", "users.read", "offline.access"] # Adjust scopes as needed
+)
+
+# Step 2: Get authorization URL
+auth_url = auth.get_authorization_url()
+print(f"Visit this URL to authorize: {auth_url}")
+webbrowser.open(auth_url)
+
+# Step 3: Handle callback (in a real app, use a web framework like Flask)
+# Assume callback_url = "http://localhost:8080/callback?code=AUTH_CODE_HERE"
+callback_url = input("Paste the full callback URL here: ")
+parsed = urlparse(callback_url)
+code = parsed.query.split("=")[1]
+
+# Step 4: Exchange code for tokens
+tokens = auth.fetch_token(authorization_code=code)
+access_token = tokens["access_token"]
+refresh_token = tokens["refresh_token"] # Store for renewal
+
+# Step 5: Create client
+client = Client(oauth2_access_token=access_token)
+```
+
+**Token Refresh** (automatic in SDK for long-lived sessions):
+
+```python
+# If access token expires, refresh using stored refresh_token
+tokens = auth.refresh_token(refresh_token=refresh_token)
+client = Client(oauth2_access_token=tokens["access_token"])
+```
+
+### 3. OAuth 1.0a User Context
+
+For legacy endpoints that require OAuth 1.0 support.
+
+**Steps**:
+
+1. Generate Consumer Key/Secret and Access Token/Secret via Developer Portal.
+
+2. Pass it when initializing the client.
+
+**Example**:
+
+```python
+from xdk.auth import OAuth1User
+
+auth = OAuth1User(
+ consumer_key="your_consumer_key",
+ consumer_secret="your_consumer_secret",
+ access_token="your_access_token",
+ access_token_secret="your_access_token_secret"
+)
+
+client = Client(auth=auth)
+```
+
+**Note**:
+
+- Never hardcode secrets in production; use environment variables or secret managers (e.g., `os.getenv("X_BEARER_TOKEN")`).
+
+- For PKCE, ensure HTTPS for redirect URIs in production.
+
+- The SDK validates tokens and raises `xdk.AuthenticationError` on failures.
+'''
+
+ (output_dir / 'xdks' / 'python' / 'authentication.mdx').write_text(auth_content)
+
+ # Pagination page
+ pagination_content = '''---
+title: Pagination
+sidebarTitle: Pagination
+---
+
+The X API uses pagination for endpoints that return multiple pages of results (e.g. timelines, search etc.). Each API call response includes a `meta` object with `result_count`, `previous_token`, and `next_token`. The XDK takes care of making multiple API calls using the `next_token` so developers can just specify how much data they are looking for without having to make multiple calls.
+
+The SDK simplifies this with:
+
+- **Built-in Iterators**: Use generator functions for seamless multi-page fetching.
+
+- **Explicit Token Handling**: For flexible manual control when needed by passing `pagination_token` when needed.
+
+- **Max Results Enforcement**: Respect `max_results` per call (up to API limits, e.g., 100 for search).
+
+## Automatic Pagination (Recommended)
+
+Use the `iterate()` method on paginated responses to fetch all results lazily.
+
+**Example: Paginated Search**
+
+```python
+from xdk import Client
+
+client = Client(bearer_token="your_bearer_token")
+
+# Search with automatic pagination
+all_posts = []
+for page in client.posts.search_recent(
+ query="python",
+ max_results=100, # Per page
+ tweetfields=["created_at", "author_id"] # Optional expansions
+):
+ all_posts.extend(page.data)
+ print(f"Fetched {len(page.data)} Posts (total: {len(all_posts)})")
+
+print(f"Total tweets: {len(all_posts)}")
+```
+
+- The iterator handles `next_token` automatically.
+
+- Stops when no `next_token` is present.
+
+- Supports rate limit backoff to avoid 429 errors.
+
+## Manual Pagination
+
+If you require control over the results for some custom logic (e.g. processing page-by-page), you can still use the `next_token` and do the pagination manually as shown below:
+
+```python
+response = client.posts.search_recent(
+ query="xdk python sdk",
+ max_results=100,
+ pagination_token=None # First page
+)
+
+print(f"First page: {len(response.data)} Posts")
+
+next_token = response.meta.next_token
+if next_token:
+ next_response = client.posts.search_recent(
+ query="xdk python sdk",
+ max_results=100,
+ pagination_token=next_token
+ )
+ print(f"Second page: {len(next_response.data)} Posts")
+```
+
+**Tips**:
+
+- Always specify `max_results` to optimize (default varies by endpoint).
+
+- Monitor `meta.result_count` for debugging.
+
+- For very large queries, consider async iteration to avoid blocking.
+'''
+
+ (output_dir / 'xdks' / 'python' / 'pagination.mdx').write_text(pagination_content)
+
+ # Streaming page
+ streaming_content = '''---
+title: Streaming
+sidebarTitle: Streaming
+---
+
+The X API supports real-time data via endpoints like the [Filtered Stream Endpoint](https://docs.x.com/x-api/posts/filtered-stream/introduction), delivering matching Posts as they occur. This requires making a persistent http connection.
+
+## Setup and Basic Streaming
+
+### Synchronous
+
+```python
+from xdk import Client
+
+# Initialize client
+client = Client(bearer_token="your_bearer_token")
+
+# Stream posts (make sure you have rules set up first)
+for post_response in client.stream.posts():
+ data = post_response.model_dump()
+
+ if 'data' in data and data['data']:
+ tweet = data['data']
+ print(f"Post: {tweet.get('text', '')}")
+```
+
+### Async
+
+```python
+import asyncio
+from asyncio import Queue
+import threading
+from xdk import Client
+
+async def stream_posts_async(client: Client):
+ queue = Queue()
+ loop = asyncio.get_event_loop()
+ stop = threading.Event()
+
+ def run_stream():
+ for post in client.stream.posts():
+ if stop.is_set():
+ break
+ asyncio.run_coroutine_threadsafe(queue.put(post), loop)
+ asyncio.run_coroutine_threadsafe(queue.put(None), loop)
+
+ threading.Thread(target=run_stream, daemon=True).start()
+
+ while True:
+ post = await queue.get()
+ if post is None:
+ break
+ data = post.model_dump()
+ if 'data' in data and data['data']:
+ print(f"Post: {data['data'].get('text', '')}")
+ stop.set()
+
+async def main():
+ client = Client(bearer_token="your_bearer_token")
+ await stream_posts_async(client)
+
+asyncio.run(main())
+```
+
+## Rule Management
+
+Rules define filters on what specific data you are looking for(e.g. keywords, users etc). You can learn more about how to build rules using [this guide](https://docs.x.com/x-api/posts/filtered-stream/integrate/build-a-rule)
+
+**Adding Rules**:
+
+```python
+from xdk.stream.models import UpdateRulesRequest
+
+# Add a rule
+add_rules = {
+ "add": [
+ {"value": "from:xdevelopers", "tag": "official_updates"}
+ ]
+}
+
+request_body = UpdateRulesRequest(**add_rules)
+response = client.stream.update_rules(body=request_body)
+```
+
+**Deleting Rules**:
+
+```python
+from xdk.stream.models import UpdateRulesRequest
+
+delete_rules = {
+ "delete": {
+ "ids": ["rule_id_1", "rule_id_2"]
+ }
+}
+
+request_body = UpdateRulesRequest(**delete_rules)
+response = client.stream.update_rules(body=request_body)
+```
+
+**Listing Rules**:
+
+```python
+response = client.stream.get_rules()
+
+# Print rules
+for rule in response.data:
+ print(f"ID: {rule.id}, Value: {rule.value}, Tag: {rule.tag}")
+```
+
+For full rule syntax, see [X Streaming Rules Docs](https://developer.x.com/en/docs/twitter-api/tweets/filtered-stream/integrate/build-a-rule).
+
+## Troubleshooting
+
+- **403 Forbidden**: Invalid auth or insufficient permissions.
+
+- **420 Enhance Your Calm**: Rate limited; wait and retry.
+
+- **No Data**: Check rules with `get_rules()`; ensure matching Posts exist.
+
+For more examples and API reference, see the inline docstrings (e.g., `help(client.tweets.search_recent)`) or the generated stubs in the source. Contribute feedback via the [GitHub repo](https://github.com/xdevplatform/xdk/tree/main/xdk/python).
+'''
+
+ (output_dir / 'xdks' / 'python' / 'streaming.mdx').write_text(streaming_content)
+
+ # Create navigation structure
+ print('⚙️ Creating navigation structure...')
+
+ # Build API Reference groups
+ ref_root = output_dir / 'xdks' / 'python' / 'reference'
+ classes_dir = ref_root / 'classes'
+ modules_dir = ref_root / 'modules'
+
+ def list_files_no_ext(directory):
+ try:
+ return [
+ f'xdks/python/reference/{directory.name}/{f.stem}'
+ for f in directory.glob('*.mdx')
+ ]
+ except:
+ return []
+
+ classes_pages = list_files_no_ext(classes_dir) if classes_dir.exists() else []
+ modules_pages = list_files_no_ext(modules_dir) if modules_dir.exists() else []
+
+ # Group pages by module prefix
+ MODULE_PREFIXES = [
+ 'AccountActivity', 'Activity', 'Communities', 'CommunityNotes', 'Compliance',
+ 'Connections', 'DirectMessages', 'General', 'Lists', 'Media', 'Posts',
+ 'Spaces', 'Stream', 'Trends', 'Usage', 'Users', 'Webhooks', 'Client',
+ 'Paginator', 'OAuth2'
+ ]
+
+ def group_pages(pages, kind):
+ buckets = {}
+ for p in pages:
+ name = Path(p).stem
+ group = None
+ for pref in MODULE_PREFIXES:
+ if name.startswith(pref):
+ group = pref
+ break
+ if not group:
+ if kind == 'classes':
+ if name.endswith('Client'):
+ group = 'Clients'
+ elif 'Stream' in name:
+ group = 'Streaming'
+ elif 'Paginator' in name:
+ group = 'Pagination'
+ else:
+ group = 'Core'
+ else:
+ group = 'Misc'
+ if group not in buckets:
+ buckets[group] = []
+ buckets[group].append(p)
+
+ # Sort pages within groups
+ for group in buckets:
+ buckets[group].sort()
+
+ return [
+ {'group': k, 'pages': v}
+ for k, v in sorted(buckets.items())
+ ]
+
+ class_groups = group_pages(classes_pages, 'classes')
+ module_groups = group_pages(modules_pages, 'modules')
+
+ # Process modules.md to create accordion structure
+ modules_md_path = docs_dir / 'modules.md'
+ if modules_md_path.exists():
+ modules_raw = modules_md_path.read_text(encoding='utf-8')
+ # Extract title
+ title_match = re.search(r'^#\s+(.+)$', modules_raw, re.MULTILINE)
+ modules_title = title_match.group(1).strip() if title_match else 'Modules'
+
+ # Parse the modules structure and convert to accordion
+ # Instead of parsing modules.md, use the actual reference files we have
+ # Group by package name from actual files
+ packages = {}
+
+ # Get all reference files
+ ref_root = output_dir / 'xdks' / 'python' / 'reference'
+ all_ref_files = [f for f in ref_root.glob('*.mdx') if f.stem not in ['modules', 'index']]
+
+ # Group files by package
+ for ref_file in all_ref_files:
+ name = ref_file.stem
+ # Extract package name
+ if '.client' in name:
+ package_name = name.replace('xdk.', '').replace('.client', '')
+ module_type = 'Client'
+ elif '.models' in name:
+ package_name = name.replace('xdk.', '').replace('.models', '')
+ module_type = 'Models'
+ else:
+ # Other modules like xdk.client, xdk.paginator
+ parts = name.replace('xdk.', '').split('.')
+ package_name = parts[0] if parts else 'Core'
+ module_type = parts[-1].capitalize() if len(parts) > 1 else 'Core'
+
+ # Convert to display name
+ package_display = ' '.join(word.capitalize() for word in package_name.split('_'))
+
+ if package_display not in packages:
+ packages[package_display] = []
+
+ # Add module link
+ packages[package_display].append({
+ 'name': module_type,
+ 'link': f'xdks/python/reference/{name}'
+ })
+
+ # Build accordion content
+ package_accordions = []
+ for package_name, modules in sorted(packages.items()):
+ if modules:
+ module_items = '\n'.join([
+ f' - [{m["name"]}](/{m["link"]})'
+ for m in sorted(modules, key=lambda x: x['name'])
+ ])
+ package_accordions.append(
+ f' \n{module_items}\n '
+ )
+
+ # Build final modules content
+ if package_accordions:
+ modules_content = f'''---
+title: "{modules_title}"
+sidebarTitle: "{modules_title}"
+---
+
+
+
+
+
+{chr(10).join(package_accordions)}
+
+
+
+
+'''
+ else:
+ modules_content = f'''---
+title: "{modules_title}"
+sidebarTitle: "{modules_title}"
+---
+
+
+
+
+
+
+
+'''
+
+ # Write modules.mdx
+ (output_dir / 'xdks' / 'python' / 'reference' / 'modules.mdx').write_text(modules_content, encoding='utf-8')
+
+ # Get all reference files for navigation
+ ref_root = output_dir / 'xdks' / 'python' / 'reference'
+ all_ref_files = [f for f in ref_root.glob('*.mdx') if f.stem != 'modules' and f.stem != 'index']
+
+ # Separate into clients, models, and other
+ client_files = [f for f in all_ref_files if f.stem.endswith('.client')]
+ model_files = [f for f in all_ref_files if f.stem.endswith('.models')]
+ other_files = [f for f in all_ref_files if not f.stem.endswith('.client') and not f.stem.endswith('.models')]
+
+ # Group by package
+ def group_by_package(files):
+ buckets = {}
+ for f in files:
+ name = f.stem
+ if '.client' in name:
+ package = name.replace('xdk.', '').replace('.client', '')
+ elif '.models' in name:
+ package = name.replace('xdk.', '').replace('.models', '')
+ else:
+ parts = name.replace('xdk.', '').split('.')
+ package = parts[0] if parts else 'Core'
+
+ # Convert to display name
+ package_display = ' '.join(word.capitalize() for word in package.split('_'))
+
+ if package_display not in buckets:
+ buckets[package_display] = []
+ buckets[package_display].append(f'xdks/python/reference/{f.stem}')
+
+ # Sort pages within groups
+ for group in buckets:
+ buckets[group].sort()
+
+ return [
+ {'group': k, 'pages': v}
+ for k, v in sorted(buckets.items())
+ ]
+
+ client_groups = group_by_package(client_files)
+ model_groups = group_by_package(model_files)
+ other_groups = group_by_package(other_files)
+
+ # Generate navigation JSON
+ # Build navigation structure with packages and modules in sidebar
+ api_ref_pages = ['xdks/python/reference/modules']
+
+ # Add client groups
+ if client_groups:
+ api_ref_pages.append({
+ 'group': 'Clients',
+ 'pages': client_groups
+ })
+
+ # Add model groups
+ if model_groups:
+ api_ref_pages.append({
+ 'group': 'Models',
+ 'pages': model_groups
+ })
+
+ # Add other groups
+ if other_groups:
+ api_ref_pages.append({
+ 'group': 'Core',
+ 'pages': other_groups
+ })
+
+ python_sdk_navigation = {
+ 'tab': 'Python SDK',
+ 'hidden': True,
+ 'pages': [
+ 'xdks/python/overview',
+ 'xdks/python/install',
+ 'xdks/python/quickstart',
+ 'xdks/python/authentication',
+ 'xdks/python/pagination',
+ 'xdks/python/streaming',
+ {
+ 'group': 'API Reference',
+ 'pages': api_ref_pages
+ }
+ ]
+ }
+
+ # Write navigation JSON
+ nav_json_path = output_dir / 'python-sdk-navigation.json'
+ nav_json_path.write_text(json.dumps(python_sdk_navigation, indent=2))
+
+ print('✅ Python SDK documentation processed successfully!')
+ print(f'📁 Output directory: {output_dir}/')
+ print(f'📊 Processed {len(processed_files)} files')
+ print('\n🚀 Integration steps:')
+ print('1. Copy the \'xdks/\' folder to your existing Mintlify site')
+ print('2. Add the navigation structure from \'python-sdk-navigation.json\' to your mintlify.json')
+ print('3. Push to your main branch to deploy')
+
+ except Exception as error:
+ print(f'❌ Error processing documentation: {error}')
+ import traceback
+ traceback.print_exc()
+ sys.exit(1)
+
+if __name__ == '__main__':
+ process_docs()
+
diff --git a/xdk-gen/templates/python/pyproject_toml.j2 b/xdk-gen/templates/python/pyproject_toml.j2
index b143835e..68db66bf 100644
--- a/xdk-gen/templates/python/pyproject_toml.j2
+++ b/xdk-gen/templates/python/pyproject_toml.j2
@@ -45,6 +45,10 @@ dev = [
"pytest",
"pytest-cov",
"ruff",
+ "sphinx>=7.0.0",
+ "myst-parser>=2.0.0",
+ "sphinx-markdown-builder>=0.5.5",
+ "watchdog>=3.0.0",
]
[tool.pytest.ini_options]
diff --git a/xdk-gen/templates/python/sphinx_conf.j2 b/xdk-gen/templates/python/sphinx_conf.j2
new file mode 100644
index 00000000..ac213277
--- /dev/null
+++ b/xdk-gen/templates/python/sphinx_conf.j2
@@ -0,0 +1,99 @@
+# AUTO-GENERATED FILE - DO NOT EDIT
+# This file was automatically generated by the XDK build tool.
+# Any manual changes will be overwritten on the next generation.
+
+# Configuration file for the Sphinx documentation builder.
+#
+# For the full list of built-in configuration values, see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+import sys
+from pathlib import Path
+
+# Add the xdk package to the path so autodoc can find it
+sys.path.insert(0, str(Path(__file__).parent.parent))
+
+# -- Project information -----------------------------------------------------
+
+project = 'X API SDK'
+copyright = '2024, X Developer Platform'
+author = 'X Developer Platform'
+release = '{{ version }}'
+version = '{{ version }}'
+
+# -- General configuration ----------------------------------------------------
+
+extensions = [
+ 'sphinx.ext.autodoc',
+ 'sphinx.ext.autosummary',
+ 'sphinx.ext.viewcode',
+ 'sphinx.ext.napoleon', # Support for Google/NumPy style docstrings
+ 'myst_parser', # Markdown support
+]
+
+# Napoleon settings for docstring parsing
+napoleon_google_docstring = True
+napoleon_numpy_docstring = True
+napoleon_include_init_with_doc = False
+napoleon_include_private_with_doc = False
+napoleon_include_special_with_doc = True
+napoleon_use_admonition_for_examples = False
+napoleon_use_admonition_for_notes = False
+napoleon_use_admonition_for_references = False
+napoleon_use_ivar = False
+napoleon_use_param = True
+napoleon_use_rtype = True
+
+# Autodoc settings
+autodoc_default_options = {
+ 'members': True,
+ 'undoc-members': False,
+ 'show-inheritance': True,
+ 'inherited-members': False,
+ 'private-members': False,
+ 'special-members': '__init__',
+}
+
+autosummary_generate = True
+
+# MyST parser settings
+myst_enable_extensions = [
+ "colon_fence",
+ "deflist",
+ "dollarmath",
+ "fieldlist",
+ "html_admonition",
+ "html_image",
+ "linkify",
+ "replacements",
+ "smartquotes",
+ "strikethrough",
+ "substitution",
+ "tasklist",
+]
+
+# Templates path
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames
+source_suffix = {
+ '.rst': 'restructuredtext',
+ '.md': 'markdown',
+}
+
+# The master toctree document
+master_doc = 'index'
+
+# The language for content autogenerated by Sphinx
+language = 'en'
+
+# -- Options for HTML output --------------------------------------------------
+
+html_theme = 'default'
+html_static_path = ['_static']
+
+# -- Options for Markdown output ----------------------------------------------
+
+# Use markdown builder
+# This will be set via command line: sphinx-build -b markdown
+
diff --git a/xdk-gen/templates/python/watch_docs.j2 b/xdk-gen/templates/python/watch_docs.j2
new file mode 100644
index 00000000..e136ceae
--- /dev/null
+++ b/xdk-gen/templates/python/watch_docs.j2
@@ -0,0 +1,111 @@
+#!/usr/bin/env python3
+"""
+AUTO-GENERATED FILE - DO NOT EDIT
+This file was automatically generated by the XDK build tool.
+Any manual changes will be overwritten on the next generation.
+
+Watch for changes and regenerate documentation automatically.
+"""
+
+import os
+import sys
+import time
+import subprocess
+from pathlib import Path
+from watchdog.observers import Observer
+from watchdog.events import FileSystemEventHandler
+
+print('🚀 Starting X API SDK Documentation Watch Server...')
+
+class DocsHandler(FileSystemEventHandler):
+ """Handle file system events for documentation regeneration."""
+
+ def __init__(self):
+ self.last_regeneration = 0
+ self.debounce_seconds = 2
+
+ def on_modified(self, event):
+ if event.is_directory:
+ return
+
+ # Only watch Python files
+ if not event.src_path.endswith('.py'):
+ return
+
+ # Skip if in docs or build directories
+ if 'docs' in event.src_path or '__pycache__' in event.src_path:
+ return
+
+ # Debounce rapid changes
+ current_time = time.time()
+ if current_time - self.last_regeneration < self.debounce_seconds:
+ return
+
+ self.last_regeneration = current_time
+ print(f'📝 File changed: {event.src_path}')
+ regenerate_docs()
+
+def regenerate_docs():
+ """Regenerate documentation."""
+ print('🔄 Regenerating documentation...')
+ try:
+ result = subprocess.run(
+ [sys.executable, 'scripts/generate-docs-simple.py'],
+ check=True,
+ capture_output=True,
+ text=True
+ )
+ print(result.stdout)
+ print('✅ Documentation regenerated successfully')
+ except subprocess.CalledProcessError as e:
+ print(f'❌ Failed to regenerate documentation: {e}')
+ print(f'stderr: {e.stderr}')
+
+def start_server():
+ """Start a simple HTTP server for docs."""
+ try:
+ import http.server
+ import socketserver
+ import threading
+
+ PORT = 8080
+ Handler = http.server.SimpleHTTPRequestHandler
+
+ def run_server():
+ with socketserver.TCPServer(("", PORT), Handler) as httpd:
+ print(f'📚 Starting documentation server on http://localhost:{PORT}')
+ httpd.serve_forever()
+
+ server_thread = threading.Thread(target=run_server, daemon=True)
+ server_thread.start()
+ return server_thread
+ except Exception as e:
+ print(f'⚠️ Could not start HTTP server: {e}')
+ return None
+
+# Initial documentation generation
+regenerate_docs()
+server_thread = start_server()
+
+# Watch for changes
+event_handler = DocsHandler()
+observer = Observer()
+
+# Watch xdk directory
+xdk_path = Path('xdk')
+if xdk_path.exists():
+ observer.schedule(event_handler, str(xdk_path), recursive=True)
+ observer.start()
+ print('👀 Watching for changes... Press Ctrl+C to stop')
+
+ try:
+ while True:
+ time.sleep(1)
+ except KeyboardInterrupt:
+ print('\n🛑 Shutting down documentation server...')
+ observer.stop()
+
+ observer.join()
+else:
+ print('⚠️ xdk directory not found')
+
diff --git a/xdk-gen/templates/typescript/generate_docs.j2 b/xdk-gen/templates/typescript/generate_docs.j2
index 3402d701..c7d2b490 100644
--- a/xdk-gen/templates/typescript/generate_docs.j2
+++ b/xdk-gen/templates/typescript/generate_docs.j2
@@ -1,5 +1,3 @@
-#!/usr/bin/env node
-
/**
* Documentation generation script for X API SDK
*
diff --git a/xdk-gen/templates/typescript/generate_docs_simple.j2 b/xdk-gen/templates/typescript/generate_docs_simple.j2
new file mode 100644
index 00000000..09ef998b
--- /dev/null
+++ b/xdk-gen/templates/typescript/generate_docs_simple.j2
@@ -0,0 +1,62 @@
+import { execSync } from 'child_process';
+import fs from 'fs';
+import path from 'path';
+
+console.log('🚀 Generating X API SDK Documentation...');
+
+// Create a temporary tsconfig that excludes problematic files
+const tsconfig = {
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "ESNext",
+ "moduleResolution": "node",
+ "allowSyntheticDefaultImports": true,
+ "esModuleInterop": true,
+ "allowJs": true,
+ "strict": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "declaration": true,
+ "outDir": "./dist",
+ "rootDir": "./src"
+ },
+ "include": [
+ "src/client.ts",
+ "src/paginator.ts",
+ "src/index.ts",
+ "src/http-client.ts"
+ ],
+ "exclude": [
+ "**/stream_client.ts",
+ "**/event_driven_stream.ts",
+ "**/stream_listener.ts",
+ "**/oauth1_auth.ts",
+ "**/oauth2_auth.ts",
+ "**/crypto_utils.ts",
+ "**/models.ts"
+ ]
+};
+
+// Write temporary tsconfig
+fs.writeFileSync('tsconfig.docs.json', JSON.stringify(tsconfig, null, 2));
+
+try {
+ // Generate documentation using the temporary tsconfig
+ execSync('npx typedoc --tsconfig tsconfig.docs.json --out docs --name "X API SDK v{{ version }}" --readme README.md --theme default --includeVersion true --excludePrivate true --excludeProtected true --excludeExternals true --excludeInternal true --searchInComments true --cleanOutputDir true', { stdio: 'inherit' });
+
+ console.log('✅ Documentation generated successfully in docs/');
+
+ // Clean up temporary file
+ fs.unlinkSync('tsconfig.docs.json');
+
+} catch (error) {
+ console.error('❌ Documentation generation failed:', error.message);
+
+ // Clean up temporary file
+ if (fs.existsSync('tsconfig.docs.json')) {
+ fs.unlinkSync('tsconfig.docs.json');
+ }
+
+ process.exit(1);
+}
+
diff --git a/xdk-gen/templates/typescript/gitignore.j2 b/xdk-gen/templates/typescript/gitignore.j2
new file mode 100644
index 00000000..c09dae3f
--- /dev/null
+++ b/xdk-gen/templates/typescript/gitignore.j2
@@ -0,0 +1,15 @@
+# Documentation generation outputs
+# These are generated by the docs scripts and should not be committed
+
+# TypeDoc output directories
+docs/
+docs/html/
+docs/markdown/
+docs/api/
+
+# Mintlify processed documentation
+mintlify-docs/
+
+# Temporary files created during doc generation
+tsconfig.docs.json
+
diff --git a/xdk-gen/templates/typescript/package_json.j2 b/xdk-gen/templates/typescript/package_json.j2
index 1530112c..c45dcdd4 100644
--- a/xdk-gen/templates/typescript/package_json.j2
+++ b/xdk-gen/templates/typescript/package_json.j2
@@ -102,10 +102,10 @@
"test:coverage": "jest --coverage",
"docs": "typedoc",
"docs:build": "typedoc && echo \"Documentation generated in docs/\"",
- "docs:build-simple": "node generate-docs-simple.js",
+ "docs:build-simple": "node scripts/generate-docs-simple.js",
"docs:serve": "npx http-server docs -p 8080 -o",
- "docs:watch": "node watch-docs.js",
- "docs:mintlify": "node process-for-mintlify.js"
+ "docs:watch": "node scripts/watch-docs.js",
+ "docs:mintlify": "node scripts/process-for-mintlify.js"
},
"prettier": {
"semi": true,
diff --git a/xdk-gen/templates/typescript/process_for_mintlify.j2 b/xdk-gen/templates/typescript/process_for_mintlify.j2
new file mode 100644
index 00000000..33366963
--- /dev/null
+++ b/xdk-gen/templates/typescript/process_for_mintlify.j2
@@ -0,0 +1,1240 @@
+import { execSync } from 'child_process';
+import fs from 'fs';
+import path from 'path';
+
+console.log('🚀 Processing X API SDK Documentation for Mintlify...');
+
+// Mintlify configuration
+const MINTLIFY_CONFIG = {
+ outputDir: 'mintlify-docs',
+ baseUrl: 'https://docs.x.com',
+ title: 'X API SDK v{{ version }}',
+ description: 'TypeScript SDK for the X API with comprehensive pagination, authentication, and streaming support.',
+ version: '{{ version }}',
+ githubUrl: 'https://github.com/xdevplatform/xsdk',
+ logo: {
+ light: '/logo-light.svg',
+ dark: '/logo-dark.svg'
+ }
+};
+
+// (Removed legacy category mappings and method groups)
+
+// Helper function to generate Mintlify frontmatter
+function generateFrontmatter(title, sidebarTitle = null) {
+ // Clean up titles by removing generic type parameters for better readability
+ const cleanTitle = (str) => {
+ if (typeof str !== 'string') return str;
+ return str
+ .replace(/<.*?>/g, '') // Remove all generic type parameters
+ .replace(/Interface:\s+/, '') // Remove "Interface:" prefix
+ .replace(/Class:\s+/, '') // Remove "Class:" prefix
+ .replace(/\\/g, '') // Remove any backslashes
+ .replace(/\s+/g, ' ') // Normalize whitespace
+ .trim();
+ };
+
+ const frontmatter = {
+ title: cleanTitle(title)
+ };
+
+ if (sidebarTitle) {
+ frontmatter.sidebarTitle = cleanTitle(sidebarTitle);
+ }
+
+ // Use simple quoted strings for clean frontmatter
+ return `---
+title: "${cleanTitle(title)}"
+${sidebarTitle ? `sidebarTitle: "${cleanTitle(sidebarTitle)}"` : ''}
+---
+
+`;
+}
+
+// Helper function to clean and format markdown content
+function processMarkdownContent(content, title, currentFilePath, knownTargets) {
+ // Remove TypeDoc-specific elements that don't work well in Mintlify
+ content = content
+ // Remove TypeDoc navigation elements
+ .replace(/\[\[include:.*?\]\]/g, '')
+ .replace(/\[\[include-start:.*?\]\]/g, '')
+ .replace(/\[\[include-end:.*?\]\]/g, '')
+
+ // Fix code block formatting
+ .replace(/```typescript\n/g, '```typescript\n')
+ .replace(/```javascript\n/g, '```javascript\n')
+
+ // Remove TypeDoc breadcrumbs (README/Exports)
+ .replace(/^\[[^\]]+\]\([^\)]+\)\s*\/\s*\[Exports\]\([^\)]+\)\s*\/.*\n?/m, '')
+ // Remove modules breadcrumb variant: [..](..)/ Exports
+ .replace(/^\[[^\]]+\]\([^\)]+\)\s*\/\s*Exports\s*\n?/m, '')
+ // Fix internal links → absolute Mintlify paths, preserve TypeDoc subdirs
+ // Examples:
+ // [Client](classes/Client.md) → /xdks/typescript/reference/classes/Client
+ // [deleteSubscription](AccountActivityClient.md#deletesubscription) → /xdks/typescript/reference/AccountActivityClient#deletesubscription
+ .replace(/\[([^\]]+)\]\(([^)#]+?)(?:\.(?:md|mdx))?(#[^)]+)?\)/g, (match, text, rawLinkPath, hash) => {
+ // Skip absolute URLs (http, https, mailto, tel)
+ if (/^(?:https?:|mailto:|tel:)/i.test(rawLinkPath)) {
+ return match;
+ }
+ const anchor = hash || '';
+ const linkPath = rawLinkPath.replace(/\.(?:md|mdx)$/i, '');
+ const currentDir = currentFilePath ? currentFilePath.substring(0, currentFilePath.lastIndexOf('/')) : '';
+ // Normalize relative paths
+ const joined = path.posix.normalize(path.posix.join(currentDir || '', linkPath));
+ let targetPath = joined.replace(/^\.\/?/, '').replace(/^docs\//, '');
+ // If no directory segment and a known target exists for this base name, use it
+ if (!targetPath.includes('/') && knownTargets && knownTargets.has(targetPath)) {
+ targetPath = `${knownTargets.get(targetPath)}/${targetPath}`;
+ }
+ return `[${text}](/xdks/typescript/reference/${targetPath}${anchor})`;
+ })
+
+ // Fix method signatures
+ .replace(/### (.*?)\(/g, '### `$1`(')
+
+ // Add proper spacing
+ .replace(/\n\n\n+/g, '\n\n')
+
+ // Fix parameter formatting
+ .replace(/\*\*@param\s+(\w+)\s+(.*?)\*\*/g, '**@param** `$1` - $2')
+ // Replace package placeholder with real npm package
+ .replace(/@your-org\/x-api-sdk/g, '@xdevplatform/xdk')
+ .replace(/from\s+['"]x-api-sdk['"]/g, "from '@xdevplatform/xdk'")
+ .replace(/\*\*@returns\s+(.*?)\*\*/g, '**@returns** $1')
+ .replace(/\*\*@throws\s+(.*?)\*\*/g, '**@throws** $1');
+
+ // Remove the first H1 header to avoid duplicate titles (frontmatter title will be used)
+ content = content.replace(/^\s*#\s+[^\n]+\n+/, '');
+
+ // Escape generic type angle brackets like PaginatedResponse to avoid MDX JSX parsing
+ content = content.replace(/\b([A-Z][A-Za-z0-9_]*)<([^>\n]+)>/g, (m, name, inner) => {
+ const escapedInner = inner.replace(//g, '>');
+ return `${name}<${escapedInner}>`;
+ });
+
+ // Remove explicit Table of contents blocks; Mintlify renders a sidebar TOC automatically
+ content = content.replace(/(^##\s+Table of contents\n[\s\S]*?)(?=^##\s+|^#\s+|\Z)/gmi, '');
+
+ // Convert Properties sections to Mintlify components (ResponseField/ParamField/Expandable)
+ // Check if this is an interface or class file
+ const isInterfaceOrClass = currentFilePath && (
+ currentFilePath.includes('interfaces/') ||
+ currentFilePath.includes('classes/')
+ );
+
+ if (isInterfaceOrClass && content.includes('## Properties')) {
+ const useParamField = /Options\b/i.test(currentFilePath);
+ const fieldTag = useParamField ? 'ParamField' : 'ResponseField';
+
+ // Helper to escape type strings for HTML attributes
+ const escapeType = (type) => String(type)
+ .replace(/\"/g, '"')
+ .replace(/"/g, '"')
+ .replace(//g, '>')
+ .replace(/\{/g, '{')
+ .replace(/\}/g, '}');
+
+ // Helper to parse inline object type (e.g., "{ name?: string; age: number }")
+ const parseInlineObject = (objStr) => {
+ // Remove outer braces and array brackets
+ let cleaned = objStr.trim().replace(/^\{/, '').replace(/\}\s*\[\]?\s*$/, '').trim();
+ if (!cleaned) return [];
+
+ const props = [];
+ // Split by semicolons, but be careful with nested objects
+ let depth = 0;
+ let current = '';
+ const parts = [];
+
+ for (let i = 0; i < cleaned.length; i++) {
+ const char = cleaned[i];
+ if (char === '{') depth++;
+ else if (char === '}') depth--;
+ else if (char === ';' && depth === 0) {
+ parts.push(current.trim());
+ current = '';
+ continue;
+ }
+ current += char;
+ }
+ if (current.trim()) parts.push(current.trim());
+
+ for (const part of parts) {
+ // Match: name?: type or name: type
+ const match = part.match(/^\s*([^:?]+?)\??\s*:\s*(.+?)\s*$/);
+ if (match) {
+ const propName = match[1].trim();
+ let propType = match[2].trim();
+ const isOptional = part.includes('?') && !propType.includes('?');
+
+ // Clean up type (remove extra braces if present)
+ propType = propType.replace(/^\{/, '').replace(/\}$/, '');
+
+ props.push({
+ name: propName,
+ type: propType,
+ optional: isOptional
+ });
+ }
+ }
+ return props;
+ };
+
+ // Convert markdown table to Expandable with child fields
+ const tableToExpandable = (tableLines, tagName) => {
+ const children = [];
+ for (const line of tableLines) {
+ const trimmed = line.trim();
+ // Skip header/separator rows
+ if (/^\|\s*:?-{2,}\s*\|/.test(trimmed) || /^\|\s*Name\s*\|\s*Type\s*\|\s*$/i.test(trimmed)) continue;
+ const m = trimmed.match(/^\|\s*`?([^`|]+?)`?\s*\|\s*(.+?)\s*\|$/);
+ if (!m) continue;
+ const fname = m[1].trim().replace(/\?$/, '');
+ let ftype = m[2].trim();
+ const isOptional = m[1].includes('?');
+
+ // Remove ALL backticks and backslashes from type for parsing
+ // Backticks might be around the whole type or around individual parts
+ ftype = ftype.replace(/`/g, '').replace(/\\/g, '');
+
+ // Check if type is Object[] with inline definition
+ if (/^\{[\s\S]*\}\s*\[\]\s*$/.test(ftype)) {
+ const objProps = parseInlineObject(ftype);
+ if (objProps.length > 0) {
+ const nested = objProps.map(p => {
+ const req = p.optional ? '' : ' required';
+ const cleanPType = p.type.replace(/\}\s*\[\]\s*$/, '').trim();
+ return `<${tagName} name="${p.name}" type="${escapeType(cleanPType)}"${req}>\n${tagName}>`;
+ }).join('\n\n');
+ children.push(`<${tagName} name="${fname}" type="Object[]"${isOptional ? '' : ' required'}>\n\n${nested}\n\n${tagName}>`);
+ } else {
+ children.push(`<${tagName} name="${fname}" type="Object[]"${isOptional ? '' : ' required'}>\n${tagName}>`);
+ }
+ } else if (/^\{[\s\S]*\}$/.test(ftype)) {
+ // Nested object
+ const objProps = parseInlineObject(ftype);
+ if (objProps.length > 0) {
+ const nested = objProps.map(p => {
+ const req = p.optional ? '' : ' required';
+ return `<${tagName} name="${p.name}" type="${escapeType(p.type.trim())}"${req}>\n${tagName}>`;
+ }).join('\n\n');
+ children.push(`<${tagName} name="${fname}" type="Object"${isOptional ? '' : ' required'}>\n\n${nested}\n\n${tagName}>`);
+ } else {
+ children.push(`<${tagName} name="${fname}" type="Object"${isOptional ? '' : ' required'}>\n${tagName}>`);
+ }
+ } else {
+ // Simple type
+ const cleanType = ftype;
+ children.push(`<${tagName} name="${fname}" type="${escapeType(cleanType)}"${isOptional ? '' : ' required'}>\n${tagName}>`);
+ }
+ }
+ return children;
+ };
+
+ // Convert each property section
+ // Find Properties section - match from ## Properties to end of content or next ## section
+ const propsIndex = content.indexOf('## Properties');
+ if (propsIndex !== -1) {
+ // Find where Properties section ends (next ## or end of content)
+ const afterProps = content.substring(propsIndex + '## Properties'.length);
+ const nextSection = afterProps.match(/^\s*\n+(.*?)(?=^##\s+|$)/s);
+ if (!nextSection) return content;
+
+ const propsSection = nextSection[1];
+ const convertedProps = [];
+
+ // Match each property using regex - be more flexible with matching
+ // Split by ### headers first to ensure we get complete property blocks
+ const propBlocks = propsSection.split(/(?=^###\s+)/m).filter(b => b.trim().startsWith('###'));
+
+ for (const propBlock of propBlocks) {
+ const nameMatch = propBlock.match(/^###\s+([^\n]+)\n+/);
+ if (!nameMatch) continue;
+
+ const propName = nameMatch[1].trim();
+ const propBody = propBlock.substring(nameMatch[0].length);
+
+ // Check if optional
+ const isOptional = /•\s*`?Optional`?/.test(propBody);
+
+ // Extract type first (before description extraction)
+ // Match: • Optional **name**: `type` or • **name**: type (with or without backticks)
+ // Handle cases like: `Object`, `\{ ... \}[]`, or inline types without backticks
+ const typePattern = /:\s*(?:`([^`]+)`|([^\n]+?))(?:\s*\n|$)/;
+ const typeMatch = propBody.match(typePattern);
+ let typeStr = 'any';
+
+ if (typeMatch) {
+ // Prefer backtick-wrapped type, otherwise use unwrapped
+ typeStr = (typeMatch[1] || typeMatch[2] || '').trim();
+ }
+
+ // Clean up type string - remove backslashes, backticks, and extract from markdown links
+ // Handle markdown link format: [`Type`](link) -> just use "Type"
+ typeStr = typeStr.replace(/\[`([^`]+)`\]\([^\)]+\)/g, '$1');
+ typeStr = typeStr.replace(/`/g, '').replace(/\\/g, '');
+
+ // Extract description (text after type line, before "Type declaration" or "Defined in")
+ // First, find where the type line ends
+ const typeLineEnd = propBody.indexOf('\n', propBody.indexOf(':'));
+ const afterTypeLine = typeLineEnd !== -1 ? propBody.substring(typeLineEnd + 1) : propBody;
+
+ // Then extract just the description part (before Type declaration or Defined in)
+ const descMatch = afterTypeLine.match(/^([\s\S]*?)(?:\n####\s+Type declaration|\n####\s+Defined in|\n___|\n###|$)/);
+ let description = descMatch ? descMatch[1].trim() : '';
+
+ // Remove any leftover type line fragments
+ description = description
+ .replace(/^•\s*`?Optional`?\s*\*\*[^*]+\*\*:\s*`?[^`\n]+`?\s*\n*/, '')
+ .replace(/^•\s*\*\*[^*]+\*\*:\s*`?[^`\n]+`?\s*\n*/, '')
+ .replace(/^•\s*`?Optional`?\s*$/, '')
+ .trim();
+
+ // Check if there's a Type declaration table
+ const typeDeclMatch = propBody.match(/####\s+Type declaration\s*\n+([\s\S]*?)(?=\n####\s+Defined in|\n___|\n###|$)/);
+
+ if (typeDeclMatch) {
+ // Has table - convert to Expandable
+ const tableText = typeDeclMatch[1];
+ const tableLines = tableText.split('\n').filter(l => l.trim().startsWith('|'));
+ const children = tableToExpandable(tableLines, fieldTag);
+
+ if (children.length > 0) {
+ const finalType = typeStr === 'Object' || typeStr.includes('Object') ? 'Object' : typeStr;
+ const requiredAttr = isOptional ? '' : ' required';
+ const expandableContent = children.join('\n\n');
+ const descPart = description ? `${description}\n\n` : '';
+ convertedProps.push(`<${fieldTag} name="${propName}" type="${escapeType(finalType)}"${requiredAttr}>\n${descPart}\n${expandableContent}\n\n${fieldTag}>`);
+ } else {
+ const requiredAttr = isOptional ? '' : ' required';
+ const descPart = description ? `${description}\n\n` : '';
+ convertedProps.push(`<${fieldTag} name="${propName}" type="${escapeType(typeStr)}"${requiredAttr}>\n${descPart}${fieldTag}>`);
+ }
+ } else if (/^\{[\s\S]*\}\s*\[\]\s*$/.test(typeStr.replace(/`/g, ''))) {
+ // Object[] with inline definition - remove backticks and backslashes
+ const cleanTypeStr = typeStr.replace(/`/g, '').replace(/\\/g, '');
+ const objProps = parseInlineObject(cleanTypeStr);
+
+ // Clean description - remove any type definition remnants
+ description = description.replace(/\{[\s\S]*\}\s*\[\]\s*$/, '').trim();
+
+ if (objProps.length > 0) {
+ const nested = objProps.map(p => {
+ const req = p.optional ? '' : ' required';
+ const cleanPType = p.type.replace(/\}\s*\[\]\s*$/, '').trim();
+ return `<${fieldTag} name="${p.name}" type="${escapeType(cleanPType)}"${req}>\n${fieldTag}>`;
+ }).join('\n\n');
+ const requiredAttr = isOptional ? '' : ' required';
+ const descPart = description ? `${description}\n\n` : '';
+ convertedProps.push(`<${fieldTag} name="${propName}" type="Object[]"${requiredAttr}>\n${descPart}\n${nested}\n\n${fieldTag}>`);
+ } else {
+ const requiredAttr = isOptional ? '' : ' required';
+ const descPart = description ? `${description}\n\n` : '';
+ convertedProps.push(`<${fieldTag} name="${propName}" type="Object[]"${requiredAttr}>\n${descPart}${fieldTag}>`);
+ }
+ } else {
+ // Simple type or reference type
+ const cleanType = typeStr.replace(/^`|`$/g, '').replace(/\\/g, '');
+ const requiredAttr = isOptional ? '' : ' required';
+ const descPart = description ? `${description}\n\n` : '';
+ convertedProps.push(`<${fieldTag} name="${propName}" type="${escapeType(cleanType)}"${requiredAttr}>\n${descPart}${fieldTag}>`);
+ }
+ }
+
+ if (convertedProps.length > 0) {
+ // Replace the Properties section with converted content
+ const convertedContent = convertedProps.join('\n\n');
+ const beforeProps = content.substring(0, propsIndex);
+ const afterPropsStart = propsIndex + '## Properties'.length + nextSection[0].length;
+ const rest = content.substring(afterPropsStart);
+ content = beforeProps + '## Properties\n\n' + convertedContent + '\n' + rest;
+ }
+ }
+
+ // Clean up "Defined in" sections and separators
+ content = content
+ .replace(/^####\s+Defined in[\s\S]*?(?=^###\s+|^##\s+|$)/gm, '')
+ .replace(/^___\s*$/gm, '');
+
+ // Escape '<' inside component blocks to avoid MDX JSX parse issues in text like '<='
+ // But preserve JSX tags like , , etc.
+ content = content
+ .replace(/()([\s\S]*?)(<\/ResponseField>)/g, (m, open, inner, close) => {
+ // Escape '<' only when it's NOT part of a JSX tag (like or )
+ // Pattern: < followed by either a letter (JSX tag start) or /letter (JSX closing tag)
+ // Escape everything else like '<=' or '< number'
+ const escaped = inner.replace(/<(?![A-Za-z/])/g, '<');
+ return open + escaped + close;
+ })
+ .replace(/()([\s\S]*?)(<\/ParamField>)/g, (m, open, inner, close) => {
+ const escaped = inner.replace(/<(?![A-Za-z/])/g, '<');
+ return open + escaped + close;
+ });
+ }
+
+ return content;
+}
+
+// Helper function to determine category from file path
+function getCategoryFromPath(filePath) {
+ if (filePath.includes('classes/Client')) return 'Getting Started';
+ if (filePath.includes('classes/Paginator')) return 'Core Features';
+ if (filePath.includes('stream_client')) return 'Core Features';
+ if (filePath.includes('interfaces/')) return 'API Reference';
+
+ return 'API Reference';
+}
+
+// Main processing function
+async function processDocs() {
+ try {
+ // First, try to generate the documentation, but skip if it fails (e.g., Node version mismatch)
+ console.log('📚 Generating documentation...');
+ try {
+ execSync('npm run docs:build', { stdio: 'inherit' });
+ } catch (error) {
+ console.log('⚠️ TypeDoc generation failed (likely Node version issue), using existing docs if available...');
+ if (!fs.existsSync('docs') || fs.readdirSync('docs').length === 0) {
+ throw new Error('No documentation found and TypeDoc generation failed. Please upgrade Node.js to 16+ or generate docs manually.');
+ }
+ console.log('✅ Using existing documentation files');
+ }
+
+ // Create output directory
+ const outputDir = MINTLIFY_CONFIG.outputDir;
+ if (fs.existsSync(outputDir)) {
+ fs.rmSync(outputDir, { recursive: true });
+ }
+ fs.mkdirSync(outputDir, { recursive: true });
+
+ // Create subdirectories with xdks/typescript prefix
+ fs.mkdirSync(path.join(outputDir, 'xdks', 'typescript', 'reference'), { recursive: true });
+
+ console.log('📝 Processing markdown files...');
+
+ // Process all markdown files
+ const docsDir = 'docs';
+
+ // Recursive function to get all files (for Node.js < 18)
+ function getAllFiles(dir, fileList = []) {
+ const files = fs.readdirSync(dir);
+ files.forEach(file => {
+ const filePath = path.join(dir, file);
+ if (fs.statSync(filePath).isDirectory()) {
+ getAllFiles(filePath, fileList);
+ } else if (file.endsWith('.md')) {
+ // Store relative path from docsDir
+ fileList.push(path.relative(docsDir, filePath));
+ }
+ });
+ return fileList;
+ }
+
+ const files = getAllFiles(docsDir);
+
+ // Build map of known targets: baseName -> subdirectory (classes/interfaces/modules/enums)
+ const knownTargets = new Map();
+ for (const f of files) {
+ if (typeof f === 'string' && f.endsWith('.md')) {
+ const base = path.basename(f, '.md');
+ const dir = path.dirname(f).replace(/^\.$/, '');
+ if (!knownTargets.has(base) && dir && dir !== 'docs') {
+ knownTargets.set(base, dir);
+ }
+ }
+ }
+
+ const processedFiles = [];
+ const navigation = {
+ 'Getting Started': [],
+ 'Core Features': [],
+ 'API Reference': [],
+ 'Authentication': [],
+ 'Utilities': []
+ };
+
+ for (const file of files) {
+ if (file.endsWith('.md') && file !== 'README.md') {
+ const filePath = path.join(docsDir, file);
+ const content = fs.readFileSync(filePath, 'utf8');
+
+ // Extract title from content or filename
+ let title = path.basename(file, '.md');
+ const titleMatch = content.match(/^#\s+(.+)$/m);
+ if (titleMatch) {
+ title = titleMatch[1];
+ }
+
+ // Clean up title (keep original class/interface names without inserting spaces)
+ title = title
+ .replace(/^Class\s+/, '')
+ .replace(/^Interface\s+/, '')
+ .replace(/^Type\s+/, '')
+ .trim();
+
+ const category = getCategoryFromPath(file);
+ const processedContent = processMarkdownContent(content, title, file, knownTargets);
+
+ // Generate frontmatter with sidebarTitle
+ const frontmatter = generateFrontmatter(title, title);
+ const finalContent = frontmatter + processedContent;
+
+ // Determine output path with xdks/typescript prefix, preserving TypeDoc subdirectories
+ const baseName = path.basename(file, '.md');
+ const subDir = path.dirname(file); // e.g., classes, interfaces, enums
+ const targetDir = path.join(outputDir, 'xdks', 'typescript', 'reference', subDir);
+ fs.mkdirSync(targetDir, { recursive: true });
+ const outputPath = path.join(targetDir, `${baseName}.mdx`);
+
+ // Write processed file
+ fs.writeFileSync(outputPath, finalContent);
+ processedFiles.push({
+ title,
+ category,
+ path: outputPath,
+ originalPath: file
+ });
+
+ // Add to navigation with xdks/typescript prefix (preserve subdirectory)
+ if (navigation[category]) {
+ const relativeRefPath = path.join(subDir, baseName).replace(/\\/g, '/');
+ navigation[category].push({
+ title,
+ url: `xdks/typescript/reference/${relativeRefPath}`
+ });
+ }
+ }
+ }
+
+ // Create high-level documentation pages
+ console.log('📄 Creating high-level documentation pages...');
+
+ // Overview page
+ const overviewContent = `---
+title: "TypeScript XDK"
+sidebarTitle: "Overview"
+---
+
+A comprehensive TypeScript SDK for the X API (formerly Twitter API) with advanced features including smart pagination, multiple authentication methods, real-time streaming, and full type safety.
+
+## Key Features
+
+- **🔐 Authentication**: User Context (OAuth1.0a, OAuth2.0), and App-Only (Bearer token) authentication
+- **🔄 Pagination**: Automatic pagination with async iteration support
+- **📡 Streaming**: Event-driven streaming with automatic reconnection
+- **📚 Type Safety**: Complete TypeScript definitions for all endpoints and parameters
+- **🎯 Full X API Support**: Users, Posts, Lists, Bookmarks, Communities, and more
+
+## Quick Start
+
+
+
+\`\`\`typescript quickstart.ts theme={null}
+import {
+ Client,
+ type ClientConfig,
+ type Users
+} from '@xdevplatform/xdk';
+
+const config: ClientConfig = { bearerToken: 'your-bearer-token' };
+
+const client: Client = new Client(config);
+
+async function main(): Promise {
+ const userResponse: Users.GetByUsernameResponse = await client.users.getByUsername('XDevelopers');
+ const username: string = userResponse.data?.username!;
+ console.log(username);
+}
+
+main();
+\`\`\`
+
+\`\`\`javascript quickstart.js theme={null}
+import { Client } from '@xdevplatform/xdk';
+
+const client = new Client({ bearerToken: 'your-bearer-token' });
+
+const userResponse = await client.users.getByUsername('XDevelopers');
+const username = userResponse.data.username;
+console.log(username);
+\`\`\`
+
+
+
+## What's Next?
+
+- [Installation Guide](/xdks/typescript/install) - Set up the SDK in your project
+- [Authentication](/xdks/typescript/authentication) - Learn about different auth methods
+- [Pagination](/xdks/typescript/pagination) - Learn about data pagination
+- [Streaming](/xdks/typescript/streaming) - Learn about real-time data streaming
+- [API Reference](/xdks/typescript/reference/Client) - Read the complete API documentation
+`;
+
+ fs.writeFileSync(path.join(outputDir, 'xdks', 'typescript', 'overview.mdx'), overviewContent);
+
+ // Install page
+ const installContent = `---
+title: "Installation"
+sidebarTitle: "Installation"
+---
+
+Get started with the TypeScript SDK for X API in your project.
+
+## Install
+
+
+
+\`\`\`bash npm theme={null}
+npm install @xdevplatform/xdk
+\`\`\`
+
+\`\`\`bash yarn theme={null}
+yarn add @xdevplatform/xdk
+\`\`\`
+
+\`\`\`bash pnpm theme={null}
+pnpm add @xdevplatform/xdk
+\`\`\`
+
+
+
+## TypeScript Support
+
+The SDK is written in TypeScript and includes full type definitions. No additional type packages are required.
+
+## Requirements
+
+- Node.js 16+
+- TypeScript 4.5+ (if using TypeScript)
+
+## Next Steps
+
+- [Authentication](/xdks/typescript/authentication) - Set up authentication
+- [Quick Start](/xdks/typescript/overview) - Your first API call
+`;
+
+ fs.writeFileSync(path.join(outputDir, 'xdks', 'typescript', 'install.mdx'), installContent);
+
+ // Authentication page
+ const authContent = `---
+title: "Authentication"
+sidebarTitle: "Authentication"
+---
+
+The TypeScript SDK supports multiple authentication methods for different use cases.
+
+## Bearer Token (App-Only Auth)
+
+For read-only operations and public data access:
+
+
+
+\`\`\`typescript quickstart.ts theme={null}
+import {
+ Client,
+ type ClientConfig,
+ type Users
+} from '@xdevplatform/xdk';
+
+const config: ClientConfig = { bearerToken: 'your-bearer-token' };
+
+const client: Client = new Client(config);
+
+async function main(): Promise {
+ const userResponse: Users.GetByUsernameResponse = await client.users.getByUsername('XDevelopers');
+ const username: string = userResponse.data?.username!;
+ console.log(username);
+}
+
+main();
+\`\`\`
+
+\`\`\`javascript quickstart.js theme={null}
+import { Client } from '@xdevplatform/xdk';
+
+const client = new Client({ bearerToken: 'your-bearer-token' });
+
+const userResponse = await client.users.getByUsername('XDevelopers');
+const username = userResponse.data.username;
+console.log(username);
+\`\`\`
+
+
+
+## OAuth 1.0a (User Context)
+
+For legacy applications or specific use cases:
+
+
+
+\`\`\`typescript oauth1.ts theme={null}
+import {
+ Client,
+ OAuth1,
+ type OAuth1Config,
+ type ClientConfig,
+ type Users
+} from '@xdevplatform/xdk';
+
+const oauth1Config: OAuth1Config = {
+ apiKey: 'your-api-key',
+ apiSecret: 'your-api-secret',
+ accessToken: 'user-access-token',
+ accessTokenSecret: 'user-access-token-secret'
+};
+
+const oauth1: OAuth1 = new OAuth1(oauth1Config);
+
+const config: ClientConfig = {
+ oauth1: oauth1,
+};
+
+const client: Client = new Client(config);
+
+async function main(): Promise {
+ const response: Users.GetMeResponse = await client.users.getMe();
+
+ const me = response.data;
+ console.log(me);
+}
+
+main();
+
+\`\`\`
+
+\`\`\`javascript oauth1.js theme={null}
+import {
+ Client,
+ type ClientConfig,
+ type Users
+} from '@xdevplatform/xdk';
+
+const config: ClientConfig = { bearerToken: 'your-bearer-token' };
+
+const client: Client = new Client(config);
+
+async function main(): Promise {
+ const userResponse: Users.GetByUsernameResponse = await client.users.getByUsername('XDevelopers');
+ const username: string = userResponse.data?.username!;
+ console.log(username);
+}
+
+main();
+
+\`\`\`
+
+
+
+## OAuth 2.0 (User Context)
+
+For user-specific operations:
+
+
+
+\`\`\`typescript oauth2.ts theme={null}
+import {
+ Client,
+ OAuth2,
+ generateCodeVerifier,
+ generateCodeChallenge,
+ type OAuth2Config,
+ type ClientConfig,
+ type OAuth2Token
+} from '@xdevplatform/xdk';
+
+(async (): Promise => {
+ const oauth2Config: OAuth2Config = {
+ clientId: 'your-client-id',
+ clientSecret: 'your-client-secret',
+ redirectUri: 'https://example.com',
+ scope: ['tweet.read', 'users.read', 'offline.access'],
+ };
+
+ const oauth2: OAuth2 = new OAuth2(oauth2Config);
+
+ const state: string = 'example-state';
+ const codeVerifier: string = generateCodeVerifier();
+ const codeChallenge: string = await generateCodeChallenge(codeVerifier);
+
+ oauth2.setPkceParameters(codeVerifier, codeChallenge);
+
+ const authUrl: string = await oauth2.getAuthorizationUrl(state);
+
+ const tokens: OAuth2Token = await oauth2.exchangeCode(authCode, codeVerifier);
+
+ const config: ClientConfig = {
+ accessToken: tokens.access_token,
+ };
+
+ const client: Client = new Client(config);
+});
+
+\`\`\`
+
+\`\`\`javascript oauth2.js theme={null}
+import { Client, OAuth2, generateCodeVerifier, generateCodeChallenge } from '@xdevplatform/xdk';
+
+(async () => {
+ const oauth2 = new OAuth2({
+ clientId: 'your-client-id',
+ clientSecret: 'your-client-secret',
+ redirectUri: 'https://example.com',
+ scope: ['tweet.read', 'users.read', 'offline.access'],
+ });
+
+ const state = 'example-state';
+ const codeVerifier = generateCodeVerifier();
+ const codeChallenge = await generateCodeChallenge(codeVerifier);
+ oauth2.setPkceParameters(codeVerifier, codeChallenge);
+ const authUrl = await oauth2.getAuthorizationUrl(state);
+
+ const tokens = await oauth2.exchangeCode(authCode, codeVerifier);
+
+ const client = new Client({ accessToken: tokens.access_token });
+
+ const response = await client.users.getMe();
+ const me = response.data;
+ console.log(me);
+});
+\`\`\`
+
+
+
+## Environment Variables
+
+Store sensitive credentials in environment variables:
+
+\`\`\`bash
+# .env
+X_API_BEARER_TOKEN=your-bearer-token
+X_API_CLIENT_ID=your-client-id
+X_API_CLIENT_SECRET=your-client-secret
+\`\`\`
+
+
+
+\`\`\`typescript env.ts theme={null}
+import { Client } from '@xdevplatform/xdk';
+
+const client = new Client({ bearerToken: process.env.X_API_BEARER_TOKEN });
+\`\`\`
+
+\`\`\`javascript env.js theme={null}
+import { Client } from '@xdevplatform/xdk';
+
+const client = new Client({ bearerToken: process.env.X_API_BEARER_TOKEN });
+\`\`\`
+
+
+`;
+
+ fs.writeFileSync(path.join(outputDir, 'xdks', 'typescript', 'authentication.mdx'), authContent);
+
+ // Pagination page
+ const paginationContent = `---
+title: "Pagination"
+sidebarTitle: "Pagination"
+---
+
+The SDK provides generic paginator utilities you can use with any endpoint that returns paginated responses. Methods return plain responses; you wrap them with a paginator.
+
+### Basic Pagination
+
+
+
+\`\`\`typescript quick-start.ts theme={null}
+import { Client, UserPaginator, PaginatedResponse, Schemas } from '@xdevplatform/xdk';
+
+const client: Client = new Client({ bearerToken: 'your-bearer-token' });
+
+// Wrap any list endpoint with proper typing
+const followers: UserPaginator = new UserPaginator(
+ async (token?: string): Promise> => {
+ const res = await client.users.getFollowers('', {
+ maxResults: 100,
+ paginationToken: token,
+ userFields: ['id','name','username'],
+ });
+ return {
+ data: res.data ?? [],
+ meta: res.meta,
+ includes: res.includes,
+ errors: res.errors
+ };
+ }
+);
+\`\`\`
+
+\`\`\`javascript quick-start.js theme={null}
+import { Client } from '@xdevplatform/xdk';
+import { UserPaginator } from '@xdevplatform/xdk';
+
+const client = new Client({ bearerToken: 'your-bearer-token' });
+
+const followers = new UserPaginator(async (token) => {
+ const res = await client.users.getFollowers('', {
+ maxResults: 100,
+ paginationToken: token,
+ userFields: ['id','name','username'],
+ });
+ return { data: res.data ?? [], meta: res.meta, includes: res.includes, errors: res.errors };
+});
+\`\`\`
+
+
+
+### Manual paging
+
+
+
+\`\`\`typescript manual.ts theme={null}
+import { UserPaginator, Schemas } from '@xdevplatform/xdk';
+
+await followers.fetchNext(); // first page
+while (!followers.done) {
+ await followers.fetchNext(); // subsequent pages
+}
+
+const userCount: number = followers.users.length; // all fetched users
+const firstUser: Schemas.User | undefined = followers.users[0];
+const nextToken: string | undefined = followers.meta?.next_token;
+\`\`\`
+
+\`\`\`javascript manual.js theme={null}
+await followers.fetchNext();
+while (!followers.done) await followers.fetchNext();
+console.log(followers.items.length);
+\`\`\`
+
+
+
+### Async iteration
+
+
+
+\`\`\`typescript async.ts theme={null}
+import { Schemas } from '@xdevplatform/xdk';
+
+for await (const user of followers) {
+ const typedUser: Schemas.User = user;
+ console.log(typedUser.username); // fully typed access
+}
+\`\`\`
+
+\`\`\`javascript async.js theme={null}
+for await (const user of followers) {
+ console.log(user.username);
+}
+\`\`\`
+
+
+
+### Next page as a new instance
+
+
+
+\`\`\`typescript next.ts theme={null}
+import { UserPaginator } from '@xdevplatform/xdk';
+
+await followers.fetchNext();
+if (!followers.done) {
+ const page2: UserPaginator = await followers.next(); // independent paginator starting at next page
+ await page2.fetchNext();
+ console.log(page2.users.length); // items from second page
+}
+\`\`\`
+
+\`\`\`javascript next.js theme={null}
+await followers.fetchNext();
+if (!followers.done) {
+ const page2 = await followers.next();
+ await page2.fetchNext();
+}
+\`\`\`
+
+
+
+### Error handling and rate limits
+
+
+
+\`\`\`typescript errors.ts theme={null}
+import { UserPaginator, Schemas } from '@xdevplatform/xdk';
+
+try {
+ for await (const item of followers) {
+ const user: Schemas.User = item;
+ // process user...
+ }
+} catch (err: unknown) {
+ if (followers.rateLimited) {
+ console.error('Rate limited, backoff required');
+ // backoff / retry later
+ } else {
+ console.error('Pagination error:', err);
+ throw err;
+ }
+}
+\`\`\`
+
+\`\`\`javascript errors.js theme={null}
+try {
+ for await (const item of followers) {
+ // ...
+ }
+} catch (err) {
+ if (followers.rateLimited) {
+ // backoff / retry later
+ } else {
+ throw err;
+ }
+}
+\`\`\`
+
+
+`;
+fs.writeFileSync(path.join(outputDir, 'xdks', 'typescript', 'pagination.mdx'), paginationContent);
+
+// Streaming page
+const streamingContent = `---
+title: "Streaming"
+sidebarTitle: "Streaming"
+---
+
+The TypeScript SDK provides real-time streaming capabilities for live data feeds.
+
+## Basic Streaming
+
+Connect to real-time sampled posts:
+
+
+
+\`\`\`typescript stream.ts theme={null}
+import { Client } from '@xdevplatform/xdk';
+
+const client: Client = new Client({ bearerToken: 'your-bearer-token' });
+
+// 1% sampled public posts
+const stream = await client.stream.postsSample({
+ tweetFields: ['id','text','created_at'],
+ expansions: ['author_id'],
+ userFields: ['id','username','name']
+});
+
+// Listen to events
+stream.on('data', (event) => {
+ // event is the parsed JSON line (data/includes/matching_rules)
+ console.log('New data:', event);
+});
+
+stream.on('error', (e) => console.error('Stream error:', e));
+stream.on('close', () => console.log('Stream closed'));
+\`\`\`
+
+\`\`\`javascript stream.js theme={null}
+import { Client } from '@xdevplatform/xdk';
+
+const client = new Client({ bearerToken: 'your-bearer-token' });
+const stream = await client.stream.postsSample({ tweetfields: ['id','text'] });
+
+stream.on('data', (event) => {
+ console.log('New data:', event);
+});
+stream.on('error', (e) => console.error('Stream error:', e));
+stream.on('close', () => console.log('Stream closed'));
+\`\`\`
+
+
+
+## Async Iteration
+
+Consume the stream with async iteration:
+
+
+
+\`\`\`typescript async.ts theme={null}
+const stream = await client.stream.postsSample();
+for await (const event of stream) {
+ // Each event is a parsed JSON line (data/includes/matching_rules)
+ console.log(event);
+}
+\`\`\`
+
+\`\`\`javascript async.js theme={null}
+const stream = await client.stream.postsSample();
+for await (const event of stream) {
+ console.log(event);
+}
+\`\`\`
+
+
+
+## Stream Management
+
+Control lifecycle from the event-driven stream:
+
+\`\`\`typescript
+// Close the stream
+stream.close();
+
+// Auto-reconnect (if enabled by your wrapper)
+// The default EventDrivenStream exposes basic reconnect hooks
+\`\`\`
+
+## Error Handling
+
+Handle streaming errors and reconnections:
+
+\`\`\`typescript
+stream.on('error', (event) => {
+ const err = event.error || event;
+ console.error('Stream error:', err);
+});
+
+stream.on('keepAlive', () => {
+ // heartbeat event
+});
+\`\`\`
+`;
+fs.writeFileSync(path.join(outputDir, 'xdks', 'typescript', 'streaming.mdx'), streamingContent);
+
+ // Create navigation structure for integration into existing Mintlify site
+ console.log('⚙️ Creating navigation structure...');
+
+ // Build API Reference groups from the generated files on disk
+ const refRoot = path.join(outputDir, 'xdks', 'typescript', 'reference');
+ const classesDir = path.join(refRoot, 'classes');
+ const interfacesDir = path.join(refRoot, 'interfaces');
+
+ const listFilesNoExt = (dir) => {
+ try {
+ return fs.readdirSync(dir)
+ .filter(f => f.endsWith('.mdx'))
+ .map(f => `xdks/typescript/reference/${path.basename(dir)}/${path.basename(f, '.mdx')}`);
+ } catch (_) {
+ return [];
+ }
+ };
+
+ const classesPages = listFilesNoExt(classesDir);
+ const interfacesPages = listFilesNoExt(interfacesDir);
+
+ // Build sub-groups for Classes and Interfaces
+ const MODULE_PREFIXES = [
+ 'AccountActivity','Activity','Communities','CommunityNotes','Compliance','Connections',
+ 'DirectMessages','General','Lists','Media','Posts','Spaces','Stream','Trends','Usage',
+ 'Users','Webhooks','Http','OAuth','Client','Paginator','EventDrivenStream','StreamClient'
+ ];
+
+ function groupPages(pages, kind) {
+ const buckets = new Map();
+ for (const p of pages) {
+ const name = p.split('/').pop();
+ let group = null;
+ for (const pref of MODULE_PREFIXES) {
+ if (name.startsWith(pref)) { group = pref; break; }
+ }
+ if (!group) {
+ if (kind === 'classes') {
+ if (/Client$/.test(name)) group = 'Clients';
+ else if (/Stream/i.test(name)) group = 'Streaming';
+ else if (/Paginator$/.test(name)) group = 'Pagination';
+ else group = 'Core';
+ } else {
+ // interfaces
+ group = 'Misc';
+ }
+ }
+ if (!buckets.has(group)) buckets.set(group, []);
+ buckets.get(group).push(p);
+ }
+ // Sort pages within groups alphabetically
+ for (const [k, arr] of buckets) arr.sort();
+ // Convert to [{group, pages}]
+ return Array.from(buckets.entries()).sort((a,b)=>a[0].localeCompare(b[0])).map(([group, pages]) => ({ group, pages }));
+ }
+
+ const classGroups = groupPages(classesPages, 'classes');
+ const interfaceGroups = groupPages(interfacesPages, 'interfaces');
+
+ // Overwrite modules.mdx with an organized, expandable structure
+ const modulesOut = path.join(refRoot, 'modules.mdx');
+ // Derive original TypeDoc modules title from docs/modules.md
+ let typedocModulesTitle = 'Modules';
+ try {
+ const rawModules = fs.readFileSync(path.join('docs', 'modules.md'), 'utf8');
+ const m = rawModules.match(/^#\s+(.+)$/m);
+ if (m) typedocModulesTitle = m[1].trim();
+ } catch (_) {}
+ const renderGroupList = (groups) => groups.map(g => (
+ ` \n` +
+ g.pages.map(p => ` - [${p.split('/').pop()}](/${p})`).join('\n') +
+ `\n `
+ )).join('\n\n');
+
+ const modulesContent = `---\n`+
+`title: "${typedocModulesTitle}"\n`+
+`sidebarTitle: "${typedocModulesTitle}"\n`+
+`---\n\n`+
+`\n\n`+
+`\n\n`+
+renderGroupList(interfaceGroups)+`\n\n`+
+`\n\n`+
+`\n\n`+
+renderGroupList(classGroups)+`\n\n`+
+`\n\n`+
+`\n`;
+
+ fs.writeFileSync(modulesOut, modulesContent);
+
+ // Generate the TypeScript SDK navigation tab with requested structure
+ const typescriptSdkNavigation = {
+ tab: 'TypeScript SDK',
+ hidden: true,
+ pages: [
+ 'xdks/typescript/overview',
+ 'xdks/typescript/install',
+ 'xdks/typescript/authentication',
+ 'xdks/typescript/pagination',
+ 'xdks/typescript/streaming',
+ {
+ group: 'API Reference',
+ pages: [
+ 'xdks/typescript/reference/modules',
+ {
+ group: 'Interfaces',
+ pages: interfaceGroups
+ },
+ {
+ group: 'Classes',
+ pages: classGroups
+ }
+ ]
+ }
+ ]
+ };
+
+ // Also create a JSON file for easy copy-paste
+ fs.writeFileSync(
+ path.join(outputDir, 'typescript-sdk-navigation.json'),
+ JSON.stringify(typescriptSdkNavigation, null, 2)
+ );
+
+ console.log('✅ TypeScript SDK documentation processed successfully!');
+ console.log(`📁 Output directory: ${outputDir}/`);
+ console.log(`📊 Processed ${processedFiles.length} files`);
+ console.log('\n🚀 Integration steps:');
+ console.log('1. Copy the \'xdk/\' folder to your existing Mintlify site');
+ console.log('2. Add the navigation structure from \'typescript-sdk-navigation.json\' to your mintlify.json');
+ console.log('3. Push to your main branch to deploy');
+
+ } catch (error) {
+ console.error('❌ Error processing documentation:', error.message);
+ process.exit(1);
+ }
+}
+
+// Run the processing
+processDocs();
\ No newline at end of file
diff --git a/xdk-gen/templates/typescript/watch_docs.j2 b/xdk-gen/templates/typescript/watch_docs.j2
new file mode 100644
index 00000000..971ac6c6
--- /dev/null
+++ b/xdk-gen/templates/typescript/watch_docs.j2
@@ -0,0 +1,68 @@
+import { execSync } from 'child_process';
+import { watch } from 'chokidar';
+import { spawn } from 'child_process';
+
+console.log('🚀 Starting X API SDK Documentation Watch Server...');
+
+let serverProcess = null;
+
+function startServer() {
+ if (serverProcess) {
+ serverProcess.kill();
+ }
+
+ console.log('📚 Starting documentation server on http://localhost:8080');
+ serverProcess = spawn('npx', ['http-server', 'docs', '-p', '8080', '-o'], {
+ stdio: 'inherit'
+ });
+}
+
+function regenerateDocs() {
+ console.log('🔄 Regenerating documentation...');
+ try {
+ execSync('node scripts/generate-docs-simple.js', { stdio: 'inherit' });
+ console.log('✅ Documentation regenerated successfully');
+ } catch (error) {
+ console.error('❌ Failed to regenerate documentation:', error.message);
+ }
+}
+
+// Initial documentation generation
+regenerateDocs();
+startServer();
+
+// Watch for changes in source files
+const watcher = watch([
+ 'src/**/*.ts',
+ '!src/**/stream_client.ts',
+ '!src/**/event_driven_stream.ts',
+ '!src/**/stream_listener.ts',
+ '!src/**/oauth1_auth.ts',
+ '!src/**/oauth2_auth.ts',
+ '!src/**/crypto_utils.ts'
+], {
+ ignored: /(^|[\/\\])\../, // ignore dotfiles
+ persistent: true
+});
+
+watcher.on('change', (path) => {
+ console.log(`📝 File changed: ${path}`);
+ regenerateDocs();
+});
+
+watcher.on('error', (error) => {
+ console.error('❌ Watcher error:', error);
+});
+
+// Graceful shutdown
+process.on('SIGINT', () => {
+ console.log('\n🛑 Shutting down documentation server...');
+ if (serverProcess) {
+ serverProcess.kill();
+ }
+ watcher.close();
+ process.exit(0);
+});
+
+console.log('👀 Watching for changes... Press Ctrl+C to stop');
+
diff --git a/xdk/python/.gitignore b/xdk/python/.gitignore
new file mode 100644
index 00000000..74828e39
--- /dev/null
+++ b/xdk/python/.gitignore
@@ -0,0 +1,46 @@
+# AUTO-GENERATED FILE - DO NOT EDIT
+# This file was automatically generated by the XDK build tool.
+# Any manual changes will be overwritten on the next generation.
+# Documentation generation outputs
+# These are generated by the docs scripts and should not be committed
+
+# Sphinx output directories
+docs/
+docs/_build/
+docs_source/
+
+# Mintlify processed documentation
+mintlify-docs/
+
+# Python cache
+__pycache__/
+*.py[cod]
+*$py.class
+*.so
+.Python
+
+# Virtual environments
+venv/
+env/
+ENV/
+.venv
+
+# IDE
+.vscode/
+.idea/
+*.swp
+*.swo
+
+# Distribution / packaging
+dist/
+build/
+*.egg-info/
+
+# Testing
+.pytest_cache/
+.coverage
+htmlcov/
+
+# Type checking
+.mypy_cache/
+.pytype/
diff --git a/xdk/python/conf.py b/xdk/python/conf.py
new file mode 100644
index 00000000..91b4962f
--- /dev/null
+++ b/xdk/python/conf.py
@@ -0,0 +1,101 @@
+# AUTO-GENERATED FILE - DO NOT EDIT
+# This file was automatically generated by the XDK build tool.
+# Any manual changes will be overwritten on the next generation.
+# AUTO-GENERATED FILE - DO NOT EDIT
+# This file was automatically generated by the XDK build tool.
+# Any manual changes will be overwritten on the next generation.
+
+# Configuration file for the Sphinx documentation builder.
+#
+# For the full list of built-in configuration values, see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+import sys
+from pathlib import Path
+
+# Add the xdk package to the path so autodoc can find it
+sys.path.insert(0, str(Path(__file__).parent.parent))
+
+# -- Project information -----------------------------------------------------
+
+project = "X API SDK"
+copyright = "2024, X Developer Platform"
+author = "X Developer Platform"
+release = "0.2.2-beta"
+version = "0.2.2-beta"
+
+# -- General configuration ----------------------------------------------------
+
+extensions = [
+ "sphinx.ext.autodoc",
+ "sphinx.ext.autosummary",
+ "sphinx.ext.viewcode",
+ "sphinx.ext.napoleon", # Support for Google/NumPy style docstrings
+ "myst_parser", # Markdown support
+]
+
+# Napoleon settings for docstring parsing
+napoleon_google_docstring = True
+napoleon_numpy_docstring = True
+napoleon_include_init_with_doc = False
+napoleon_include_private_with_doc = False
+napoleon_include_special_with_doc = True
+napoleon_use_admonition_for_examples = False
+napoleon_use_admonition_for_notes = False
+napoleon_use_admonition_for_references = False
+napoleon_use_ivar = False
+napoleon_use_param = True
+napoleon_use_rtype = True
+
+# Autodoc settings
+autodoc_default_options = {
+ "members": True,
+ "undoc-members": False,
+ "show-inheritance": True,
+ "inherited-members": False,
+ "private-members": False,
+ "special-members": "__init__",
+}
+
+autosummary_generate = True
+
+# MyST parser settings
+myst_enable_extensions = [
+ "colon_fence",
+ "deflist",
+ "dollarmath",
+ "fieldlist",
+ "html_admonition",
+ "html_image",
+ "linkify",
+ "replacements",
+ "smartquotes",
+ "strikethrough",
+ "substitution",
+ "tasklist",
+]
+
+# Templates path
+templates_path = ["_templates"]
+
+# The suffix(es) of source filenames
+source_suffix = {
+ ".rst": "restructuredtext",
+ ".md": "markdown",
+}
+
+# The master toctree document
+master_doc = "index"
+
+# The language for content autogenerated by Sphinx
+language = "en"
+
+# -- Options for HTML output --------------------------------------------------
+
+html_theme = "default"
+html_static_path = ["_static"]
+
+# -- Options for Markdown output ----------------------------------------------
+
+# Use markdown builder
+# This will be set via command line: sphinx-build -b markdown
diff --git a/xdk/python/pyproject.toml b/xdk/python/pyproject.toml
index eeef0ccb..89197666 100644
--- a/xdk/python/pyproject.toml
+++ b/xdk/python/pyproject.toml
@@ -48,6 +48,10 @@ dev = [
"pytest",
"pytest-cov",
"ruff",
+ "sphinx>=7.0.0",
+ "myst-parser>=2.0.0",
+ "sphinx-markdown-builder>=0.5.5",
+ "watchdog>=3.0.0",
]
[tool.pytest.ini_options]
diff --git a/xdk/python/scripts/generate-docs-simple.py b/xdk/python/scripts/generate-docs-simple.py
new file mode 100644
index 00000000..855c7ad2
--- /dev/null
+++ b/xdk/python/scripts/generate-docs-simple.py
@@ -0,0 +1,184 @@
+# AUTO-GENERATED FILE - DO NOT EDIT
+# This file was automatically generated by the XDK build tool.
+# Any manual changes will be overwritten on the next generation.
+#!/usr/bin/env python3
+"""
+AUTO-GENERATED FILE - DO NOT EDIT
+This file was automatically generated by the XDK build tool.
+Any manual changes will be overwritten on the next generation.
+
+Generate API documentation for the Python SDK using Sphinx with markdown output.
+"""
+
+import os
+import sys
+import shutil
+import subprocess
+from pathlib import Path
+
+print("🚀 Generating X API SDK Documentation...")
+
+# Try to use virtual environment if available
+venv_python = Path(".venv") / "bin" / "python"
+if venv_python.exists():
+ print("📦 Using virtual environment...")
+ python_exe = str(venv_python)
+else:
+ python_exe = sys.executable
+
+# Configuration
+DOCS_DIR = Path("docs")
+SPHINX_SOURCE_DIR = Path("docs_source")
+SPHINX_BUILD_DIR = DOCS_DIR / "_build"
+SPHINX_MARKDOWN_DIR = DOCS_DIR
+
+# Clean up old docs
+if DOCS_DIR.exists():
+ shutil.rmtree(DOCS_DIR)
+DOCS_DIR.mkdir(parents=True, exist_ok=True)
+
+# Clean up old source
+if SPHINX_SOURCE_DIR.exists():
+ shutil.rmtree(SPHINX_SOURCE_DIR)
+
+# Create Sphinx source directory structure
+SPHINX_SOURCE_DIR.mkdir(parents=True, exist_ok=True)
+(SPHINX_SOURCE_DIR / "_static").mkdir(exist_ok=True)
+(SPHINX_SOURCE_DIR / "_templates").mkdir(exist_ok=True)
+
+# Copy conf.py from root (should be generated)
+conf_py_path = Path("conf.py")
+if conf_py_path.exists():
+ shutil.copy(conf_py_path, SPHINX_SOURCE_DIR / "conf.py")
+else:
+ print("⚠️ Warning: conf.py not found. Sphinx may not work correctly.")
+
+try:
+ # Use sphinx-apidoc to auto-generate API documentation
+ print("📚 Running sphinx-apidoc to generate API documentation structure...")
+ apidoc_cmd = [
+ python_exe,
+ "-m",
+ "sphinx.ext.apidoc",
+ "-o",
+ str(SPHINX_SOURCE_DIR),
+ "-f", # Force overwrite
+ "--separate", # Put each module in its own file
+ "xdk", # Source package
+ ]
+
+ subprocess.run(apidoc_cmd, check=True, capture_output=True, text=True)
+
+ # Create or update index.rst
+ index_content = """X API SDK Documentation
+==========================
+
+Welcome to the X API SDK documentation.
+
+.. toctree::
+ :maxdepth: 2
+ :caption: API Reference:
+
+ modules
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+"""
+
+ (SPHINX_SOURCE_DIR / "index.rst").write_text(index_content)
+
+ # Run Sphinx with markdown builder
+ print("📚 Running Sphinx to generate markdown documentation...")
+
+ sphinx_cmd = [
+ python_exe,
+ "-m",
+ "sphinx",
+ "-b",
+ "markdown", # Use markdown builder
+ str(SPHINX_SOURCE_DIR),
+ str(SPHINX_MARKDOWN_DIR),
+ ]
+
+ result = subprocess.run(sphinx_cmd, check=True, capture_output=True, text=True)
+ print("✅ Documentation generated successfully in docs/")
+
+ # Clean up build directory
+ if SPHINX_BUILD_DIR.exists():
+ shutil.rmtree(SPHINX_BUILD_DIR)
+
+ # Clean up source directory
+ if SPHINX_SOURCE_DIR.exists():
+ shutil.rmtree(SPHINX_SOURCE_DIR)
+
+except subprocess.CalledProcessError as e:
+ print(f"❌ Documentation generation failed: {e}")
+ if e.stdout:
+ print(f"stdout: {e.stdout}")
+ if e.stderr:
+ print(f"stderr: {e.stderr}")
+ sys.exit(1)
+except FileNotFoundError:
+ print("❌ Sphinx not found.")
+ print("💡 Installing dependencies...")
+ try:
+ # Try to install using uv if available
+ if shutil.which("uv"):
+ subprocess.run(
+ ["uv", "pip", "install", "-e", ".[dev]"], check=True, shell=False
+ )
+ else:
+ # Fallback to pip
+ subprocess.run(
+ [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ "sphinx",
+ "myst-parser",
+ "sphinx-markdown-builder",
+ ],
+ check=True,
+ )
+ print("✅ Dependencies installed. Please run the script again.")
+ except subprocess.CalledProcessError:
+ print("❌ Failed to install dependencies automatically.")
+ print("💡 Please install manually with:")
+ print(" uv pip install -e '.[dev]'")
+ print(" or")
+ print(" pip install sphinx myst-parser sphinx-markdown-builder")
+ sys.exit(1)
+except ImportError as e:
+ if "myst_parser" in str(e) or "myst-parser" in str(e):
+ print("❌ myst-parser not found.")
+ print("💡 Installing dependencies...")
+ try:
+ if shutil.which("uv"):
+ subprocess.run(
+ ["uv", "pip", "install", "-e", ".[dev]"], check=True, shell=False
+ )
+ else:
+ subprocess.run(
+ [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ "myst-parser",
+ "sphinx-markdown-builder",
+ ],
+ check=True,
+ )
+ print("✅ Dependencies installed. Please run the script again.")
+ except subprocess.CalledProcessError:
+ print("❌ Failed to install dependencies automatically.")
+ print("💡 Please install manually with:")
+ print(" uv pip install -e '.[dev]'")
+ else:
+ raise
+ sys.exit(1)
diff --git a/xdk/python/scripts/process-for-mintlify.py b/xdk/python/scripts/process-for-mintlify.py
new file mode 100644
index 00000000..f193e2da
--- /dev/null
+++ b/xdk/python/scripts/process-for-mintlify.py
@@ -0,0 +1,1972 @@
+# AUTO-GENERATED FILE - DO NOT EDIT
+# This file was automatically generated by the XDK build tool.
+# Any manual changes will be overwritten on the next generation.
+#!/usr/bin/env python3
+"""
+AUTO-GENERATED FILE - DO NOT EDIT
+This file was automatically generated by the XDK build tool.
+Any manual changes will be overwritten on the next generation.
+
+Process Sphinx-generated markdown documentation for Mintlify.
+"""
+
+import os
+import sys
+import json
+import re
+import shutil
+from pathlib import Path
+from typing import Dict, List, Optional, Set
+
+print("🚀 Processing X API SDK Documentation for Mintlify...")
+
+# Mintlify configuration
+MINTLIFY_CONFIG = {
+ "outputDir": "mintlify-docs",
+ "baseUrl": "https://docs.x.com",
+ "title": "X API SDK v0.2.2-beta",
+ "description": "Python SDK for the X API with comprehensive pagination, authentication, and streaming support.",
+ "version": "0.2.2-beta",
+ "githubUrl": "https://github.com/xdevplatform/xdk",
+}
+
+
+def clean_title(title: str, file_path: str = "", content: str = "") -> str:
+ """Clean and improve title formatting."""
+ if not isinstance(title, str):
+ title = str(title)
+ # Try to extract class name from content first (more reliable)
+ if content:
+ # Look for class definition: ### *class* xdk.module.ClassName
+ class_match = re.search(
+ r"\*class\*\s+[^\s]*\.([A-Z][a-zA-Z0-9_]*Client|Client|Paginator|OAuth2PKCEAuth)\b",
+ content,
+ )
+ if class_match:
+ return class_match.group(1)
+ # Remove module suffix
+ title = re.sub(r"\s+module\s*$", "", title, flags=re.IGNORECASE)
+ # Extract class name from patterns like "xdk.users.client.UsersClient"
+ class_match = re.search(
+ r"\.([A-Z][a-zA-Z0-9_]+Client|Paginator|OAuth2PKCEAuth)\b", title
+ )
+ if class_match:
+ return class_match.group(1)
+ # Fallback to generic Client only if no specific client found
+ if "Client" in title and not re.search(r"[A-Z][a-zA-Z0-9_]+Client", title):
+ class_match = re.search(r"\.(Client)\b", title)
+ if class_match:
+ return class_match.group(1)
+ # Extract class name from patterns like "*class* xdk.users.client.UsersClient"
+ class_match2 = re.search(
+ r"\*class\*\s+[^\s]*\.([A-Z][a-zA-Z0-9_]*Client|Client|Paginator|OAuth2PKCEAuth)\b",
+ title,
+ )
+ if class_match2:
+ return class_match2.group(1)
+ # Remove xdk. prefix
+ title = re.sub(r"^xdk\.", "", title)
+ # Convert snake_case to PascalCase for module names
+ if "." in title and not title[0].isupper():
+ parts = title.split(".")
+ # Capitalize each part
+ title = ".".join(p.capitalize() for p in parts)
+ # Clean up
+ title = (
+ re.sub(r"<.*?>", "", title) # Remove generic type parameters
+ .replace("Class: ", "")
+ .replace("Interface: ", "")
+ .replace("*class*", "")
+ .replace("*", "")
+ .replace("\\", "")
+ .replace("\n", " ")
+ .strip()
+ )
+ return title
+
+
+def generate_frontmatter(
+ title: str, sidebar_title: Optional[str] = None, file_path: str = ""
+) -> str:
+ """Generate Mintlify frontmatter."""
+ cleaned_title = clean_title(title, file_path)
+ cleaned_sidebar = (
+ clean_title(sidebar_title, file_path) if sidebar_title else cleaned_title
+ )
+ frontmatter = f'title: "{cleaned_title}"\n'
+ if sidebar_title:
+ frontmatter += f'sidebarTitle: "{cleaned_sidebar}"\n'
+ return f"---\n{frontmatter}---\n\n"
+
+
+def reorganize_class_structure(content: str, file_path: str) -> str:
+ """Reorganize content into proper sections like TypeScript."""
+ # Check if this is a class/client file
+ if "client" not in file_path.lower() and "models" not in file_path.lower():
+ return content
+ # Find class definition - handle both formats
+ # Pattern 1: ### *class* xdk.module.ClassName(params)
+ # Pattern 2: ### `*class* xdk.module.ClassName`(params)
+ class_match = re.search(
+ r"###\s+(?:`?)?\*class\*\s+([^\n(]+)(?:`?)?\s*\(([^)]*)\)", content
+ )
+ if not class_match:
+ return content
+ class_name_full = class_match.group(1).strip().replace("*", "").replace("`", "")
+ # Extract just the class name (last part after last dot)
+ class_name = (
+ class_name_full.split(".")[-1] if "." in class_name_full else class_name_full
+ )
+ class_params = class_match.group(2).strip()
+ # Extract description after class definition
+ class_start = class_match.end()
+ next_section = content.find("###", class_start)
+ if next_section == -1:
+ next_section = len(content)
+ description = content[class_start:next_section].strip()
+ # Extract "Bases:" line for later use as Badge
+ bases_match = re.search(r"Bases:\s*`([^`]+)`", description, re.IGNORECASE)
+ bases = bases_match.group(1).strip() if bases_match else None
+ # Remove "Bases:" line - we'll add it as a Badge
+ description = re.sub(
+ r"Bases:\s*`[^`]+`\s*\n?", "", description, flags=re.IGNORECASE
+ )
+ # Remove any stray closing parentheses
+ description = re.sub(r"^\)\s*\n?", "", description)
+ description = description.strip()
+ # Find all methods and properties
+ methods = []
+ constructors = []
+ properties = []
+ # Pattern for methods: ### method_name(params) → ReturnType
+ method_pattern = r"###\s+`?([^\n(]+)`?\s*\(([^)]*)\)(?:\s*→\s*([^\n]+))?"
+ for match in re.finditer(method_pattern, content):
+ method_name = (
+ match.group(1).strip().replace("`", "").replace("\\", "").replace("*", "")
+ )
+ params = match.group(2).strip()
+ return_type = match.group(3).strip() if match.group(3) else None
+ # Find method body
+ method_start = match.start()
+ next_method = content.find("###", method_start + 1)
+ if next_method == -1:
+ method_body = content[method_start:]
+ else:
+ method_body = content[method_start:next_method]
+ method_info = {
+ "name": method_name,
+ "params": params,
+ "return_type": return_type,
+ "body": method_body,
+ }
+ if method_name == "__init__" or "constructor" in method_name.lower():
+ constructors.append(method_info)
+ elif method_name.startswith("property") or "property" in method_body.lower():
+ properties.append(method_info)
+ else:
+ methods.append(method_info)
+ # Rebuild content with proper sections
+ sections = []
+ # Class definition and description
+ sections.append(f"## {class_name}\n\n")
+ sections.append('Class\n')
+ if bases:
+ sections.append(f'\nBases: {bases}\n')
+ if description:
+ sections.append(f"\n{description}\n")
+ # Constructors section
+ if constructors:
+ sections.append("\n## Constructors\n")
+ for const in constructors:
+ sections.append(const["body"])
+ # Methods section
+ if methods:
+ sections.append("\n## Methods\n")
+ for method in methods:
+ sections.append(method["body"])
+ # Properties section
+ if properties:
+ sections.append("\n## Properties\n")
+ for prop in properties:
+ sections.append(prop["body"])
+ # If we found methods/constructors, rebuild content
+ if constructors or methods or properties:
+ before_class = content[: class_match.start()]
+ # Get remaining content after last method
+ if methods:
+ last_method_end = content.rfind(methods[-1]["body"])
+ remaining = content[last_method_end + len(methods[-1]["body"]) :]
+ elif constructors:
+ last_constructor_end = content.rfind(constructors[-1]["body"])
+ remaining = content[last_constructor_end + len(constructors[-1]["body"]) :]
+ else:
+ remaining = content[next_section:]
+ # Clean up any stray characters and duplicate class definitions
+ remaining = re.sub(r"^\)\s*\n", "", remaining)
+ # Remove duplicate class definitions that might have been left behind
+ # Pattern: ### `class xdk.module.ClassName` followed by description and parameters
+ # Match the full duplicate class definition block
+ remaining = re.sub(
+ r"###\s+`?class\s+xdk\.[^\n]+\n\n[^\n]+\n\n(?:####\s+Parameters[^\n]+\n\n]+>\s*\s*\n)?",
+ "",
+ remaining,
+ )
+ # Also remove any standalone class definitions without parameters
+ remaining = re.sub(
+ r"###\s+`?\*?class\*?\s+xdk\.[^\n]+\n\n[^\n]+\n\n", "", remaining
+ )
+ # Remove any remaining class definition patterns (more aggressive)
+ remaining = re.sub(
+ r"###\s+`?class\s+[^\n]+\n\n[^\n]+\n\n(?:####\s+Parameters[^\n]+\n\n)?",
+ "",
+ remaining,
+ )
+ return before_class + "\n".join(sections) + remaining
+ return content
+
+
+def clean_class_definitions(content: str) -> str:
+ """Clean up class definition headers."""
+ # Remove any remaining class definition headers that weren't processed
+ # Pattern: ### `*class* xdk.module.ClassName`(params) or ## xdk.module.ClassName
+ # These should already be converted by reorganize_class_structure, but clean up any leftovers
+ # Remove any stray class definition patterns
+ content = re.sub(r"##\s+xdk\.[^\n]+\n\n\)\s*\n", "", content)
+ # Clean up any remaining "Bases:" lines that weren't converted
+ content = re.sub(r"^Bases:\s*`[^`]+`\s*\n?", "", content, flags=re.MULTILINE)
+ return content
+
+
+def fix_method_names(content: str) -> str:
+ """Fix method names with escaped underscores."""
+ # Pattern: ### ``\_\_init_\_`` -> ### `__init__`
+ # Handle double backticks with escaped underscores
+ content = re.sub(r"###\s+``\\?(_+[^`]+_+)``", r"### `\1`", content)
+ # Pattern: ### ``method\_name`` -> ### `method_name`
+ content = re.sub(r"###\s+``([^`]*)\\?(_[^`]*)``", r"### `\1\2`", content)
+ # Pattern: ### ``\_\_init_\_``(params) -> ### `__init__`(params)
+ content = re.sub(r"###\s+``([^`]*)\\?(_[^`]*)``\s*\(", r"### `\1\2`(", content)
+ # Remove any remaining escaped underscores in method names (single backticks)
+ content = re.sub(r"###\s+`([^`]*)\\?(_[^`]*)`\s*\(", r"### `\1\2`(", content)
+ # Fix any remaining escaped underscores in code blocks
+ content = re.sub(r"`([^`]*)\\?(_[^`]*)`", r"`\1\2`", content)
+ return content
+
+
+def improve_method_formatting(content: str) -> str:
+ """Improve method formatting to match TypeScript style with ParamField components."""
+ # Pattern: ### method_name(params) → ReturnType
+ def convert_method(match):
+ method_header = match.group(0)
+ method_name = (
+ match.group(1)
+ .strip()
+ .replace("*", "")
+ .replace("`", "")
+ .replace("\\", "")
+ .replace("_", "_")
+ )
+ params_str = match.group(2).strip() if match.group(2) else ""
+ return_type = match.group(3).strip() if match.group(3) else None
+ # Find method body (until next ### or ####)
+ method_start = match.start()
+ next_method = content.find("###", method_start + 1)
+ if next_method == -1:
+ method_body = content[method_start:]
+ else:
+ method_body = content[method_start:next_method]
+ # Extract description (text after method header, before :param)
+ desc_match = re.search(
+ r"###[^\n]+\n\n([^\n]+(?:\n(?!:param|####|###|####)[^\n]+)*)",
+ method_body,
+ re.MULTILINE,
+ )
+ description = desc_match.group(1).strip() if desc_match else ""
+ # Remove method name from description if it appears
+ description = re.sub(
+ r"^" + re.escape(method_name) + r"\s*$", "", description, flags=re.MULTILINE
+ ).strip()
+ # Parse parameters and convert to ParamField components
+ param_fields = []
+ if params_str:
+ # Simple parameter parsing (split by comma, but handle type annotations)
+ params = []
+ current = ""
+ depth = 0
+ for char in params_str:
+ if char in "[(":
+ depth += 1
+ elif char in "])":
+ depth -= 1
+ elif char == "," and depth == 0:
+ if current.strip():
+ params.append(current.strip())
+ current = ""
+ continue
+ current += char
+ if current.strip():
+ params.append(current.strip())
+ for param in params:
+ # Parse: name: type = default
+ # Handle cases like: client: [Client](xdk.md#xdk.Client)
+ param_match = re.match(
+ r"(\w+)(?:\s*:\s*([^=]+))?(?:\s*=\s*(.+))?$", param.strip()
+ )
+ if param_match:
+ param_name = param_match.group(1)
+ param_type_raw = (
+ param_match.group(2).strip() if param_match.group(2) else "Any"
+ )
+ param_default = (
+ param_match.group(3).strip() if param_match.group(3) else None
+ )
+ # Clean type - handle markdown links first
+ # Pattern: [Type](path#anchor) -> extract just "Type"
+ link_match = re.search(r"\[([^\]]+)\]\(([^\)]+)\)", param_type_raw)
+ if link_match:
+ param_type = link_match.group(1) # Use just the link text
+ else:
+ # No link, use the raw type but clean it
+ param_type = param_type_raw
+ # Remove file references and anchors
+ param_type = re.sub(r"[a-z_]+\.(md|py)#[^\s]*", "", param_type)
+ param_type = re.sub(r"#[^\s]*", "", param_type)
+ # Remove incomplete link patterns like "Client]("
+ param_type = re.sub(r"\]\([^\)]*$", "", param_type)
+ param_type = re.sub(r"\]\([^\)]*\)", "", param_type)
+ # Clean up the type string
+ param_type = param_type.replace("|", " or ").strip()
+ # Remove any trailing/leading brackets and parentheses
+ param_type = re.sub(r"^[\[\(]+", "", param_type)
+ param_type = re.sub(r"[\]\)]+$", "", param_type)
+ # Remove any remaining incomplete patterns
+ param_type = re.sub(r"\]\(.*$", "", param_type)
+ # Escape angle brackets for MDX
+ param_type = param_type.replace("<", "<").replace(">", ">")
+ # Clean up extra spaces
+ param_type = re.sub(r"\s+", " ", param_type).strip()
+ # If type is empty or just brackets, default to Any
+ if not param_type or param_type in ["[", "]", "()", "(", ")", "]("]:
+ param_type = "Any"
+ # Find param description
+ param_desc_match = re.search(
+ rf":param\s+{param_name}:\s*([^\n]+)", method_body
+ )
+ param_desc = (
+ param_desc_match.group(1).strip() if param_desc_match else ""
+ )
+ # Build ParamField - use path instead of name
+ # For Python methods, parameters are function arguments
+ # Use "path" location for most parameters, or "body" if it's clearly a request body
+ param_location = (
+ "body"
+ if param_name.lower() in ["body", "data", "payload", "request"]
+ else "path"
+ )
+ param_field = f'", ">")
+ )
+ param_field += f' default="{param_default_clean}"'
+ param_field += ">"
+ if param_desc:
+ param_field += f"\n{param_desc}\n"
+ param_field += ""
+ param_fields.append(param_field)
+ # Build new method format
+ new_method = f"### `{method_name}`\n\n"
+ if description:
+ new_method += f"{description}\n\n"
+ if param_fields:
+ new_method += "#### Parameters\n\n"
+ new_method += "\n\n".join(param_fields) + "\n\n"
+ if return_type:
+ # Extract return description
+ return_desc_match = re.search(r":param\s+Returns?:\s*([^\n]+)", method_body)
+ return_desc = (
+ return_desc_match.group(1).strip() if return_desc_match else ""
+ )
+ # Clean return type - handle markdown links
+ return_type_clean = re.sub(r"\[([^\]]+)\]\([^\)]+\)", r"\1", return_type)
+ return_type_clean = re.sub(
+ r"[a-z_]+\.(md|py)#[^\s]+", "", return_type_clean
+ )
+ return_type_clean = return_type_clean.replace("[", "").replace("]", "")
+ return_type_clean = return_type_clean.replace("<", "<").replace(
+ ">", ">"
+ )
+ return_type_clean = re.sub(
+ r":param\s+\w+:\s*", "", return_type_clean
+ ).strip()
+ return_type_clean = re.sub(r"\s+", " ", return_type_clean).strip()
+ new_method += "#### Returns\n\n"
+ new_method += f"`{return_type_clean}`"
+ if return_desc and return_desc != return_type_clean:
+ new_method += f" - {return_desc}"
+ new_method += "\n\n"
+ return new_method
+ # Convert method signatures to use ParamField components
+ # Match: ### method_name(params) → ReturnType
+ def process_all_methods(text):
+ # Find all method definitions
+ method_pattern = r"###\s+`?([^\n(]+)`?\s*\(([^)]*)\)(?:\s*→\s*([^\n]+))?"
+ methods = list(re.finditer(method_pattern, text, re.MULTILINE))
+ if not methods:
+ return text
+ # Build result by processing each method and replacing its entire section
+ result_parts = []
+ last_pos = 0
+ for i, match in enumerate(methods):
+ # Add content before this method
+ result_parts.append(text[last_pos : match.start()])
+ # Find where this method's body ends (next method or end of content)
+ method_start = match.start()
+ if i + 1 < len(methods):
+ next_method_start = methods[i + 1].start()
+ else:
+ next_method_start = len(text)
+ # Get the full method section to replace
+ method_section = text[method_start:next_method_start]
+ # Convert this method
+ converted = convert_method(match)
+ # Remove the old method content from the section
+ result_parts.append(converted)
+ last_pos = next_method_start
+ # Add remaining content
+ result_parts.append(text[last_pos:])
+ return "".join(result_parts)
+ content = process_all_methods(content)
+ # Clean up any remaining :param lines that weren't converted
+ content = re.sub(r":param\s+(\w+):\s*([^\n]+)", r"**`\1`** - \2", content)
+ content = re.sub(r":param\s+Returns?:\s*([^\n]+)", r"**Returns:** \1", content)
+ # Remove duplicate return descriptions
+ content = re.sub(
+ r"(#### Returns\n\n`[^\n]+`[^\n]+\n\n)(\*\*`[^\n]+\*\*[^\n]+\n)+",
+ r"\1",
+ content,
+ )
+ # Remove duplicate method descriptions
+ content = re.sub(r"(### `[^\n]+`\n\n[^\n]+\n\n[^\n]+\n\n)(\1)", r"\1", content)
+ # Clean up any remaining old format parameter lines after ParamField sections
+ content = re.sub(r"(\n\n)(\*\*`[^\n]+\*\*[^\n]+\n)+", r"\1", content)
+ # Remove duplicate "Returns:" text in return sections
+ content = re.sub(
+ r"(#### Returns\n\n`[^\n]+`)\s*-\s*\*\*`[^\n]+\*\*\s*-\s*([^\n]+)",
+ r"\1 - \2",
+ content,
+ )
+ # Remove duplicate class definitions that appear after the main class header
+ # Pattern: ### `class xdk.module.ClassName` followed by description and parameters
+ # Find the main class header (should be ## ClassName)
+ main_class_match = re.search(
+ r"##\s+([A-Z][a-zA-Z0-9_]+Client|Client|Paginator|OAuth2PKCEAuth|BaseModel)",
+ content,
+ )
+ if main_class_match:
+ # Everything after the main class header should not have duplicate class definitions
+ before_main = content[: main_class_match.end()]
+ after_main = content[main_class_match.end() :]
+ # Remove any class definitions from after_main
+ after_main = re.sub(
+ r"###\s+`?class\s+xdk\.[^\n]+\n\n[^\n]+\n\n(?:####\s+Parameters[^\n]+\n\n]+>\s*\s*\n)?",
+ "",
+ after_main,
+ )
+ content = before_main + after_main
+ # Remove duplicate parameter sections (#### Parameters appearing twice in a row)
+ content = re.sub(
+ r"(#### Parameters\n\n]+>\s*\s*\n)\1", r"\1", content
+ )
+ return content
+
+
+ def convert_method(match):
+ method_header = match.group(0)
+ method_name = (
+ match.group(1)
+ .strip()
+ .replace("*", "")
+ .replace("`", "")
+ .replace("\\", "")
+ .replace("_", "_")
+ )
+ params_str = match.group(2).strip() if match.group(2) else ""
+ return_type = match.group(3).strip() if match.group(3) else None
+ # Find method body (until next ### or ####)
+ method_start = match.start()
+ next_method = content.find("###", method_start + 1)
+ if next_method == -1:
+ method_body = content[method_start:]
+ else:
+ method_body = content[method_start:next_method]
+ # Extract description (text after method header, before :param)
+ desc_match = re.search(
+ r"###[^\n]+\n\n([^\n]+(?:\n(?!:param|####|###|####)[^\n]+)*)",
+ method_body,
+ re.MULTILINE,
+ )
+ description = desc_match.group(1).strip() if desc_match else ""
+ # Remove method name from description if it appears
+ description = re.sub(
+ r"^" + re.escape(method_name) + r"\s*$", "", description, flags=re.MULTILINE
+ ).strip()
+ # Parse parameters and convert to ParamField components
+ param_fields = []
+ if params_str:
+ # Simple parameter parsing (split by comma, but handle type annotations)
+ params = []
+ current = ""
+ depth = 0
+ for char in params_str:
+ if char in "[(":
+ depth += 1
+ elif char in "])":
+ depth -= 1
+ elif char == "," and depth == 0:
+ if current.strip():
+ params.append(current.strip())
+ current = ""
+ continue
+ current += char
+ if current.strip():
+ params.append(current.strip())
+ for param in params:
+ # Parse: name: type = default
+ # Handle cases like: client: [Client](xdk.md#xdk.Client)
+ param_match = re.match(
+ r"(\w+)(?:\s*:\s*([^=]+))?(?:\s*=\s*(.+))?$", param.strip()
+ )
+ if param_match:
+ param_name = param_match.group(1)
+ param_type_raw = (
+ param_match.group(2).strip() if param_match.group(2) else "Any"
+ )
+ param_default = (
+ param_match.group(3).strip() if param_match.group(3) else None
+ )
+ # Clean type - handle markdown links first
+ # Pattern: [Type](path#anchor) -> extract just "Type"
+ link_match = re.search(r"\[([^\]]+)\]\(([^\)]+)\)", param_type_raw)
+ if link_match:
+ param_type = link_match.group(1) # Use just the link text
+ else:
+ # No link, use the raw type but clean it
+ param_type = param_type_raw
+ # Remove file references and anchors
+ param_type = re.sub(r"[a-z_]+\.(md|py)#[^\s]*", "", param_type)
+ param_type = re.sub(r"#[^\s]*", "", param_type)
+ # Remove incomplete link patterns like "Client]("
+ param_type = re.sub(r"\]\([^\)]*$", "", param_type)
+ param_type = re.sub(r"\]\([^\)]*\)", "", param_type)
+ # Clean up the type string
+ param_type = param_type.replace("|", " or ").strip()
+ # Remove any trailing/leading brackets and parentheses
+ param_type = re.sub(r"^[\[\(]+", "", param_type)
+ param_type = re.sub(r"[\]\)]+$", "", param_type)
+ # Remove any remaining incomplete patterns
+ param_type = re.sub(r"\]\(.*$", "", param_type)
+ # Escape angle brackets for MDX
+ param_type = param_type.replace("<", "<").replace(">", ">")
+ # Clean up extra spaces
+ param_type = re.sub(r"\s+", " ", param_type).strip()
+ # If type is empty or just brackets, default to Any
+ if not param_type or param_type in ["[", "]", "()", "(", ")", "]("]:
+ param_type = "Any"
+ # Find param description
+ param_desc_match = re.search(
+ rf":param\s+{param_name}:\s*([^\n]+)", method_body
+ )
+ param_desc = (
+ param_desc_match.group(1).strip() if param_desc_match else ""
+ )
+ # Build ParamField - use path instead of name
+ # For Python methods, parameters are function arguments
+ # Use "path" location for most parameters, or "body" if it's clearly a request body
+ param_location = (
+ "body"
+ if param_name.lower() in ["body", "data", "payload", "request"]
+ else "path"
+ )
+ param_field = f'", ">")
+ )
+ param_field += f' default="{param_default_clean}"'
+ param_field += ">"
+ if param_desc:
+ param_field += f"\n{param_desc}\n"
+ param_field += ""
+ param_fields.append(param_field)
+ # Build new method format
+ new_method = f"### `{method_name}`\n\n"
+ if description:
+ new_method += f"{description}\n\n"
+ if param_fields:
+ new_method += "#### Parameters\n\n"
+ new_method += "\n\n".join(param_fields) + "\n\n"
+ if return_type:
+ # Extract return description
+ return_desc_match = re.search(r":param\s+Returns?:\s*([^\n]+)", method_body)
+ return_desc = (
+ return_desc_match.group(1).strip() if return_desc_match else ""
+ )
+ # Clean return type - handle markdown links
+ return_type_clean = re.sub(r"\[([^\]]+)\]\([^\)]+\)", r"\1", return_type)
+ return_type_clean = re.sub(
+ r"[a-z_]+\.(md|py)#[^\s]+", "", return_type_clean
+ )
+ return_type_clean = return_type_clean.replace("[", "").replace("]", "")
+ return_type_clean = return_type_clean.replace("<", "<").replace(
+ ">", ">"
+ )
+ return_type_clean = re.sub(
+ r":param\s+\w+:\s*", "", return_type_clean
+ ).strip()
+ return_type_clean = re.sub(r"\s+", " ", return_type_clean).strip()
+ new_method += "#### Returns\n\n"
+ new_method += f"`{return_type_clean}`"
+ if return_desc and return_desc != return_type_clean:
+ new_method += f" - {return_desc}"
+ new_method += "\n\n"
+ return new_method
+
+ # Convert method signatures to use ParamField components
+ # Match: ### method_name(params) → ReturnType
+
+
+ def process_all_methods(text):
+ # Find all method definitions
+ method_pattern = r"###\s+`?([^\n(]+)`?\s*\(([^)]*)\)(?:\s*→\s*([^\n]+))?"
+ methods = list(re.finditer(method_pattern, text, re.MULTILINE))
+ if not methods:
+ return text
+ # Build result by processing each method and replacing its entire section
+ result_parts = []
+ last_pos = 0
+ for i, match in enumerate(methods):
+ # Add content before this method
+ result_parts.append(text[last_pos : match.start()])
+ # Find where this method's body ends (next method or end of content)
+ method_start = match.start()
+ if i + 1 < len(methods):
+ next_method_start = methods[i + 1].start()
+ else:
+ next_method_start = len(text)
+ # Get the full method section to replace
+ method_section = text[method_start:next_method_start]
+ # Convert this method
+ converted = convert_method(match)
+ # Remove the old method content from the section
+ result_parts.append(converted)
+ last_pos = next_method_start
+ # Add remaining content
+ result_parts.append(text[last_pos:])
+ return "".join(result_parts)
+
+ content = process_all_methods(content)
+
+ # Clean up any remaining :param lines that weren't converted
+ content = re.sub(r":param\s+(\w+):\s*([^\n]+)", r"**`\1`** - \2", content)
+ content = re.sub(r":param\s+Returns?:\s*([^\n]+)", r"**Returns:** \1", content)
+
+ # Remove duplicate return descriptions
+ content = re.sub(
+ r"(#### Returns\n\n`[^\n]+`[^\n]+\n\n)(\*\*`[^\n]+\*\*[^\n]+\n)+",
+ r"\1",
+ content,
+ )
+
+ # Remove duplicate method descriptions
+ content = re.sub(r"(### `[^\n]+`\n\n[^\n]+\n\n[^\n]+\n\n)(\1)", r"\1", content)
+
+ # Clean up any remaining old format parameter lines after ParamField sections
+ content = re.sub(r"(\n\n)(\*\*`[^\n]+\*\*[^\n]+\n)+", r"\1", content)
+
+ # Remove duplicate "Returns:" text in return sections
+ content = re.sub(
+ r"(#### Returns\n\n`[^\n]+`)\s*-\s*\*\*`[^\n]+\*\*\s*-\s*([^\n]+)",
+ r"\1 - \2",
+ content,
+ )
+
+ # Remove duplicate class definitions that appear after the main class header
+ # Pattern: ### `class xdk.module.ClassName` followed by description and parameters
+ # Find the main class header (should be ## ClassName)
+ main_class_match = re.search(
+ r"##\s+([A-Z][a-zA-Z0-9_]+Client|Client|Paginator|OAuth2PKCEAuth|BaseModel)",
+ content,
+ )
+ if main_class_match:
+ # Everything after the main class header should not have duplicate class definitions
+ before_main = content[: main_class_match.end()]
+ after_main = content[main_class_match.end() :]
+
+ # Remove any class definitions from after_main
+ after_main = re.sub(
+ r"###\s+`?class\s+xdk\.[^\n]+\n\n[^\n]+\n\n(?:####\s+Parameters[^\n]+\n\n]+>\s*\s*\n)?",
+ "",
+ after_main,
+ )
+
+ content = before_main + after_main
+
+ # Remove duplicate parameter sections (#### Parameters appearing twice in a row)
+ content = re.sub(
+ r"(#### Parameters\n\n]+>\s*\s*\n)\1", r"\1", content
+ )
+
+ return content
+
+
+def process_markdown_content(
+ content: str, title: str, current_file_path: str, known_targets: Dict[str, str]
+) -> str:
+ """Process and clean markdown content for Mintlify."""
+ # Remove Sphinx-specific elements
+ content = re.sub(r"\[\[include:.*?\]\]", "", content)
+ # Fix code block formatting
+ content = re.sub(r"```python\n", "```python\n", content)
+ # Remove Sphinx breadcrumbs
+ content = re.sub(
+ r"^\[[^\]]+\]\([^\)]+\)\s*/\s*.*\n?", "", content, flags=re.MULTILINE
+ )
+ # Remove auto-generated comments at the beginning
+ # Pattern: "Auto-generated ..." followed by description paragraphs ending with "Generated automatically - do not edit manually."
+ content = re.sub(
+ r"^Auto-generated[^\n]+\n\n[^\n]+\n\n[^\n]+\n\nAll methods[^\n]+\n\nGenerated automatically[^\n]+\n\n",
+ "",
+ content,
+ flags=re.MULTILINE,
+ )
+ # Also remove variations - single line or multiple paragraphs
+ content = re.sub(r"^Auto-generated[^\n]+\n\n", "", content, flags=re.MULTILINE)
+ content = re.sub(
+ r"^This module provides[^\n]+\n\n", "", content, flags=re.MULTILINE
+ )
+ content = re.sub(r"^All methods[^\n]+\n\n", "", content, flags=re.MULTILINE)
+ content = re.sub(
+ r"^Generated automatically[^\n]+\n\n", "", content, flags=re.MULTILINE
+ )
+ # Fix method names first - remove escaped underscores (before other processing)
+ content = fix_method_names(content)
+ # Reorganize content into proper sections (Constructors, Methods, Properties)
+ content = reorganize_class_structure(content, current_file_path)
+ # Clean up class definitions - remove asterisks, format properly
+ content = clean_class_definitions(content)
+ # Improve method formatting - convert to better structure with ParamField
+ content = improve_method_formatting(content)
+ # Fix internal links to absolute Mintlify paths
+ def fix_link(match):
+ text = match.group(1)
+ raw_link_path = match.group(2)
+ hash_part = match.group(3) or ""
+ # Skip absolute URLs
+ if re.match(r"^(?:https?:|mailto:|tel:)", raw_link_path, re.I):
+ return match.group(0)
+ link_path = raw_link_path.replace(".md", "").replace(".rst", "")
+ current_dir = str(Path(current_file_path).parent) if current_file_path else ""
+ # Normalize path
+ if current_dir:
+ joined = Path(current_dir) / link_path
+ target_path = str(joined).replace("\\", "/").replace("docs/", "")
+ else:
+ target_path = link_path.replace("\\", "/").replace("docs/", "")
+ # Use known target if available
+ base_name = Path(target_path).stem
+ if base_name in known_targets and "/" not in target_path:
+ target_path = f"{known_targets[base_name]}/{base_name}"
+ return f"[{text}](/xdks/python/reference/{target_path}{hash_part})"
+ content = re.sub(
+ r"\[([^\]]+)\]\(([^)#]+?)(?:\.(?:md|rst))?(#[^)]+)?\)", fix_link, content
+ )
+ # Fix method signatures
+ content = re.sub(r"### (.*?)\(", r"### `\1`(", content)
+ # Add proper spacing
+ content = re.sub(r"\n\n\n+", "\n\n", content)
+ # Remove first H1 header (frontmatter title will be used)
+ content = re.sub(r"^\s*#\s+[^\n]+\n+", "", content)
+ # Escape generic type angle brackets (but preserve component tags)
+ # Simple approach: escape angle brackets, then fix Badge tags
+ content = re.sub(
+ r"\b([A-Z][A-Za-z0-9_]*)<([^>\n]+)>",
+ lambda m: f"{m.group(1)}<{m.group(2).replace('<', '<').replace('>', '>')}>",
+ content,
+ )
+ # Fix any escaped Badge tags (they shouldn't have angle brackets anyway)
+ content = content.replace("</Badge>", "")
+ content = content.replace("Class</Badge>", "Class")
+ content = content.replace("BaseModel</Badge>", "BaseModel")
+ # Remove Table of Contents blocks
+ content = re.sub(
+ r"(^##\s+Table of contents\n[\s\S]*?)(?=^##\s+|^#\s+|\Z)",
+ "",
+ content,
+ flags=re.MULTILINE | re.IGNORECASE,
+ )
+ # Fix asterisks around type annotations that break MDX parsing
+ # Pattern: #### field *: Type* *= value* -> #### field : Type = value
+ # This handles cases like: model_config *: ClassVar[ConfigDict]* *= {'extra': 'allow', ...}*
+ # Match: field *: Type* *= value* (where value can contain quotes, commas, etc.)
+ # Use a more specific pattern that includes the header marker
+ content = re.sub(
+ r"(####\s+\w+)\s+\*\s*:\s*([^*]+?)\s*\*\s*\*\s*=\s*([^\n]+?)\s*\*",
+ r"\1: \2 = \3",
+ content,
+ flags=re.MULTILINE,
+ )
+ # Fix asterisks around type annotations without equals (just type)
+ # Pattern: field *: Type* -> field : Type
+ content = re.sub(
+ r"(\w+)\s+\*\s*:\s*([^*\n]+?)\s*\*", r"\1: \2", content, flags=re.MULTILINE
+ )
+ # Fix remaining asterisks around equals signs (standalone)
+ # Pattern: *= value* -> = value
+ content = re.sub(r"\*\s*=\s*([^\n]+?)\s*\*", r"= \1", content, flags=re.MULTILINE)
+ # Fix asterisks around class/function names in headers
+ # Pattern: ### *class* name -> ### class name
+ content = re.sub(r"###\s+\*\s*(\w+)\s*\*\s+", r"### \1 ", content)
+ # Convert property headers with type annotations to Mintlify components
+ # This must happen AFTER asterisk removal
+ # Pattern: #### field: Type = value\n\nDescription
+ # Convert to: Description
+ def convert_property_header(match):
+ field_name = match.group(1)
+ type_and_default = match.group(2).strip()
+ description = match.group(3).strip() if match.group(3) else ""
+ # Split type and default value
+ # Format: ClassVar[ConfigDict] = {'extra': 'allow', ...}
+ type_match = re.match(r"([^=]+?)(?:\s*=\s*(.+))?$", type_and_default)
+ if type_match:
+ type_annotation = type_match.group(1).strip()
+ default_value = type_match.group(2).strip() if type_match.group(2) else None
+ else:
+ type_annotation = type_and_default
+ default_value = None
+ # Clean up type annotation - remove ClassVar, brackets, etc.
+ # ClassVar[ConfigDict] -> ConfigDict
+ type_clean = re.sub(r"ClassVar\[([^\]]+)\]", r"\1", type_annotation)
+ # Remove any remaining brackets for display
+ type_clean = type_clean.replace("[", "").replace("]", "").strip()
+ # Escape type for MDX
+ type_clean = type_clean.replace("<", "<").replace(">", ">")
+ # Build the component
+ component = f'"
+ if description:
+ component += f"\n{description}\n"
+ component += ""
+ return component
+ # Match: #### field: Type = value\n\nDescription
+ # Match the entire header line, then blank line, then description
+ content = re.sub(
+ r"####\s+(\w+)\s*:\s*([^\n]+?)\s*\n\s*\n([^\n]+(?:\n(?!####)[^\n]+)*)?",
+ convert_property_header,
+ content,
+ flags=re.MULTILINE,
+ )
+ return content
+
+
+ def fix_link(match):
+ text = match.group(1)
+ raw_link_path = match.group(2)
+ hash_part = match.group(3) or ""
+ # Skip absolute URLs
+ if re.match(r"^(?:https?:|mailto:|tel:)", raw_link_path, re.I):
+ return match.group(0)
+ link_path = raw_link_path.replace(".md", "").replace(".rst", "")
+ current_dir = str(Path(current_file_path).parent) if current_file_path else ""
+ # Normalize path
+ if current_dir:
+ joined = Path(current_dir) / link_path
+ target_path = str(joined).replace("\\", "/").replace("docs/", "")
+ else:
+ target_path = link_path.replace("\\", "/").replace("docs/", "")
+ # Use known target if available
+ base_name = Path(target_path).stem
+ if base_name in known_targets and "/" not in target_path:
+ target_path = f"{known_targets[base_name]}/{base_name}"
+ return f"[{text}](/xdks/python/reference/{target_path}{hash_part})"
+
+ content = re.sub(
+ r"\[([^\]]+)\]\(([^)#]+?)(?:\.(?:md|rst))?(#[^)]+)?\)", fix_link, content
+ )
+
+ # Fix method signatures
+ content = re.sub(r"### (.*?)\(", r"### `\1`(", content)
+
+ # Add proper spacing
+ content = re.sub(r"\n\n\n+", "\n\n", content)
+
+ # Remove first H1 header (frontmatter title will be used)
+ content = re.sub(r"^\s*#\s+[^\n]+\n+", "", content)
+
+ # Escape generic type angle brackets (but preserve component tags)
+ # Simple approach: escape angle brackets, then fix Badge tags
+ content = re.sub(
+ r"\b([A-Z][A-Za-z0-9_]*)<([^>\n]+)>",
+ lambda m: f"{m.group(1)}<{m.group(2).replace('<', '<').replace('>', '>')}>",
+ content,
+ )
+
+ # Fix any escaped Badge tags (they shouldn't have angle brackets anyway)
+ content = content.replace("</Badge>", "")
+ content = content.replace("Class</Badge>", "Class")
+ content = content.replace("BaseModel</Badge>", "BaseModel")
+
+ # Remove Table of Contents blocks
+ content = re.sub(
+ r"(^##\s+Table of contents\n[\s\S]*?)(?=^##\s+|^#\s+|\Z)",
+ "",
+ content,
+ flags=re.MULTILINE | re.IGNORECASE,
+ )
+
+ # Fix asterisks around type annotations that break MDX parsing
+ # Pattern: #### field *: Type* *= value* -> #### field : Type = value
+ # This handles cases like: model_config *: ClassVar[ConfigDict]* *= {'extra': 'allow', ...}*
+ # Match: field *: Type* *= value* (where value can contain quotes, commas, etc.)
+ # Use a more specific pattern that includes the header marker
+ content = re.sub(
+ r"(####\s+\w+)\s+\*\s*:\s*([^*]+?)\s*\*\s*\*\s*=\s*([^\n]+?)\s*\*",
+ r"\1: \2 = \3",
+ content,
+ flags=re.MULTILINE,
+ )
+
+ # Fix asterisks around type annotations without equals (just type)
+ # Pattern: field *: Type* -> field : Type
+ content = re.sub(
+ r"(\w+)\s+\*\s*:\s*([^*\n]+?)\s*\*", r"\1: \2", content, flags=re.MULTILINE
+ )
+
+ # Fix remaining asterisks around equals signs (standalone)
+ # Pattern: *= value* -> = value
+ content = re.sub(r"\*\s*=\s*([^\n]+?)\s*\*", r"= \1", content, flags=re.MULTILINE)
+
+ # Fix asterisks around class/function names in headers
+ # Pattern: ### *class* name -> ### class name
+ content = re.sub(r"###\s+\*\s*(\w+)\s*\*\s+", r"### \1 ", content)
+
+ # Convert property headers with type annotations to Mintlify components
+ # This must happen AFTER asterisk removal
+ # Pattern: #### field: Type = value\n\nDescription
+ # Convert to: Description
+
+
+ def convert_property_header(match):
+ field_name = match.group(1)
+ type_and_default = match.group(2).strip()
+ description = match.group(3).strip() if match.group(3) else ""
+ # Split type and default value
+ # Format: ClassVar[ConfigDict] = {'extra': 'allow', ...}
+ type_match = re.match(r"([^=]+?)(?:\s*=\s*(.+))?$", type_and_default)
+ if type_match:
+ type_annotation = type_match.group(1).strip()
+ default_value = type_match.group(2).strip() if type_match.group(2) else None
+ else:
+ type_annotation = type_and_default
+ default_value = None
+ # Clean up type annotation - remove ClassVar, brackets, etc.
+ # ClassVar[ConfigDict] -> ConfigDict
+ type_clean = re.sub(r"ClassVar\[([^\]]+)\]", r"\1", type_annotation)
+ # Remove any remaining brackets for display
+ type_clean = type_clean.replace("[", "").replace("]", "").strip()
+ # Escape type for MDX
+ type_clean = type_clean.replace("<", "<").replace(">", ">")
+ # Build the component
+ component = f'"
+ if description:
+ component += f"\n{description}\n"
+ component += ""
+ return component
+
+ # Match: #### field: Type = value\n\nDescription
+ # Match the entire header line, then blank line, then description
+ content = re.sub(
+ r"####\s+(\w+)\s*:\s*([^\n]+?)\s*\n\s*\n([^\n]+(?:\n(?!####)[^\n]+)*)?",
+ convert_property_header,
+ content,
+ flags=re.MULTILINE,
+ )
+
+ return content
+
+
+def get_category_from_path(file_path: str) -> str:
+ """Determine category from file path."""
+ if "client" in file_path.lower() and "Client" in file_path:
+ return "Getting Started"
+ if "paginator" in file_path.lower():
+ return "Core Features"
+ if "stream" in file_path.lower():
+ return "Core Features"
+ return "API Reference"
+
+
+def process_docs():
+ """Main processing function."""
+ try:
+ # First, try to generate documentation
+ print("📚 Generating documentation...")
+ try:
+ import subprocess
+ result = subprocess.run(
+ [sys.executable, "scripts/generate-docs-simple.py"],
+ check=True,
+ capture_output=True,
+ text=True,
+ )
+ print(result.stdout)
+ except subprocess.CalledProcessError as e:
+ print("⚠️ Sphinx generation failed, using existing docs if available...")
+ if not Path("docs").exists() or not any(Path("docs").iterdir()):
+ raise RuntimeError(
+ "No documentation found and Sphinx generation failed. "
+ "Please install Sphinx: pip install sphinx myst-parser sphinx-markdown-builder"
+ )
+ print("✅ Using existing documentation files")
+ # Create output directory
+ output_dir = Path(MINTLIFY_CONFIG["outputDir"])
+ if output_dir.exists():
+ shutil.rmtree(output_dir)
+ output_dir.mkdir(parents=True, exist_ok=True)
+ # Create subdirectories
+ (output_dir / "xdks" / "python" / "reference").mkdir(
+ parents=True, exist_ok=True
+ )
+ print("📝 Processing markdown files...")
+ # Get all markdown files
+ docs_dir = Path("docs")
+ files = list(docs_dir.rglob("*.md"))
+ # Build map of known targets
+ known_targets = {}
+ for f in files:
+ base = f.stem
+ parent = f.parent.name
+ if parent and parent != "docs" and base not in known_targets:
+ known_targets[base] = parent
+ processed_files = []
+ navigation = {
+ "Getting Started": [],
+ "Core Features": [],
+ "API Reference": [],
+ "Authentication": [],
+ "Utilities": [],
+ }
+ for file_path in files:
+ if file_path.name == "README.md":
+ continue
+ # Special handling for modules.md - convert to accordion format
+ if file_path.name == "modules.md":
+ continue # Will process separately
+ content = file_path.read_text(encoding="utf-8")
+ # Extract title
+ title_match = re.search(r"^#\s+(.+)$", content, re.MULTILINE)
+ title = title_match.group(1) if title_match else file_path.stem
+ # Clean title using improved function (pass content for better extraction)
+ cleaned_title = clean_title(title, str(file_path), content)
+ category = get_category_from_path(str(file_path))
+ processed_content = process_markdown_content(
+ content,
+ cleaned_title,
+ str(file_path.relative_to(docs_dir)),
+ known_targets,
+ )
+ # Generate frontmatter
+ frontmatter = generate_frontmatter(
+ cleaned_title, cleaned_title, str(file_path)
+ )
+ final_content = frontmatter + processed_content
+ # Determine output path
+ base_name = file_path.stem
+ sub_dir = file_path.parent.name if file_path.parent != docs_dir else ""
+ target_dir = output_dir / "xdks" / "python" / "reference" / sub_dir
+ target_dir.mkdir(parents=True, exist_ok=True)
+ output_path = target_dir / f"{base_name}.mdx"
+ # Write processed file
+ output_path.write_text(final_content, encoding="utf-8")
+ processed_files.append(
+ {
+ "title": cleaned_title,
+ "category": category,
+ "path": str(output_path),
+ "originalPath": str(file_path),
+ }
+ )
+ # Add to navigation
+ if category in navigation:
+ relative_ref_path = f"{sub_dir}/{base_name}" if sub_dir else base_name
+ navigation[category].append(
+ {
+ "title": cleaned_title,
+ "url": f"xdks/python/reference/{relative_ref_path}",
+ }
+ )
+ # Create high-level documentation pages
+ print("📄 Creating high-level documentation pages...")
+ # Overview page
+ overview_content = """---
+title: Python XDK
+sidebarTitle: Overview
+---
+The Python XDK (X Developer Kit) is our official client library for interacting with the X API v2 using Python. It allows developers to get started with our API quickly and build applications with it. It is generated based on our official [OpenAPI specification](https://api.x.com/2/openapi.json). It abstracts away low-level HTTP details while providing fine-grained control when needed.
+## Key Features
+- 🔐 **OAuth Support**: Full support for Bearer Token (app-only) auth, OAuth 2.0 with PKCE (user context), and OAuth 1.0.
+- 🔄 **Pagination**: Automatically page through large results. The XDK takes care of pagination without requiring you to make multiple API calls using the `next_token`.
+- 📡 **Streaming**: Supports real-time data streaming for endpoints like filtered stream that require persistent http connection.
+- 🎯 **Comprehensive Coverage**: Supports all X API v2 endpoints including such as search, timelines, filtered-stream and more.
+**Version Compatibility**: Python 3.8+. Tested on CPython and PyPy.
+**License**: [MIT License](https://github.com/xdevplatform/xdk/blob/main/LICENSE)
+"""
+ (output_dir / "xdks" / "python" / "overview.mdx").write_text(overview_content)
+ # Install page
+ install_content = """---
+title: "Install"
+sidebarTitle: "Install"
+---
+The XDK Python SDK is available directly from the GitHub repository and can be installed via `pip`.
+## Prerequisites
+- Python 3.8 or higher.
+- `pip` and `venv` for virtual environments (recommended).
+## Quick Install
+Install the XDK from the GitHub subdirectory:
+```bash
+pip install xdk
+```
+This fetches the latest generated version from the `main` branch.
+## Development Install
+For development or contributing:
+1. Clone the repository:
+ ```bash
+ git clone https://github.com/xdevplatform/xdk.git
+ cd xdk/python
+ ```
+2. Install dependencies in editable mode:
+ ```bash
+ pip install -e .
+ ```
+ This installs the SDK and its runtime dependencies.
+3. (Optional) Install dev dependencies for testing/linting:
+ ```bash
+ pip install -e .[dev]
+ ```
+## Verification
+Test the installation:
+```python
+import xdk
+print(xdk.__version__) # Should print the XDK version
+```
+**Note:** Since the XDK is generated using the OpenAPI spec, always check the [X API changelog](https://docs.x.com/changelog) and XDK release notes in the repo for any changes.
+"""
+ (output_dir / "xdks" / "python" / "install.mdx").write_text(install_content)
+ # Quickstart page
+ quickstart_content = """---
+title: Quickstart
+sidebarTitle: Quickstart
+---
+This example showcases how to quickly search for Posts using the XDK using Bearer Token authentication.
+## Step 1: Install the SDK
+```bash
+pip install xdk
+```
+## Step 2: Get Your Bearer Token
+1. Log in to the [X Developer Portal](https://developer.x.com/en/portal/dashboard).
+2. Create or select an app.
+3. Under "Keys and Tokens," generate a Bearer Token (app-only auth).
+## Step 3: Write and Run Your First Script
+Create a file `quickstart.py`:
+```python
+# Import the client
+from xdk import Client
+# Replace with your actual Bearer Token
+client = Client(bearer_token="YOUR_BEARER_TOKEN_HERE")
+# Fetch recent Posts mentioning "api"
+response = client.posts.search_recent(query="api", max_results=10)
+# Print the first Post's text
+if response.data:
+ print(f"Latest Post: {response.data[0]['text']}")
+else:
+ print("No Posts found.")
+```
+Run it:
+```bash
+python quickstart.py
+```
+**Expected Output**:
+```
+Latest Post: Exciting updates on XDK Python SDK!
+```
+**Troubleshooting**: If you get a 401 error, double-check your Bearer Token. For rate limits (429), wait and retry.
+## Next Steps
+- Explore [Authentication](/xdks/python/authentication) to understand how to use Bearer Token (app-only) auth, OAuth 2.0 with PKCE (user context), and OAuth 1.0.
+- Learn about [Pagination](/xdks/python/pagination) for use-cases where you want large number of results returned without worrying about making multiple API calls.
+- Dive into [Streaming](/xdks/python/streaming) to learn how to work with real-time data.
+"""
+ (output_dir / "xdks" / "python" / "quickstart.mdx").write_text(
+ quickstart_content
+ )
+ # Authentication page
+ auth_content = """---
+title: Authentication
+sidebarTitle: Authentication
+---
+The X API requires authentication for all endpoints. The XDK supports three authentication methods:
+1. Bearer Token (app-only)
+2. OAuth 2.0 with PKCE
+3. OAuth 1.0a User Context
+- **Bearer Token**: Use this for read-only access for endpoints that support app-auth (e.g., searching Post's, streaming endpoints).
+- **OAuth 2.0 PKCE**: Secure authentication for scope-based, user-authorized access (e.g. getting authenticated user's Post non_public metrics)
+- **OAuth 1.0a**: Legacy auth for full read/write access, including DMs and media uploads.
+**Note**: We recommend developers move away from OAuth 1.0 and use OAuth 2.0 for user-authorized access.
+Obtain credentials from the [X Developer Portal](https://developer.x.com/en/portal/dashboard). You'll need an approved developer account and an app with appropriate permissions (e.g., Read + Write).
+## Creating a Client
+All authentication flows create a `Client` instance:
+```python
+from xdk import Client
+```
+### 1. Bearer Token (App-Only)
+For read-only operations without user context.
+**Steps**:
+1. In the Developer Portal, generate a Bearer Token for your app.
+2. Pass it to the `Client`.
+**Example**:
+```python
+client = Client(bearer_token="XXXXX")
+```
+**Usage**:
+```python
+response = client.posts.search_recent(query="python", max_results=10)
+print(response.data[0]['text']) # Access first Post
+```
+### 2. OAuth 2.0 with PKCE (User Context)
+This example shows how to use OAuth 2.0 with Proof Key for Code Exchange (PKCE). Use this for user-specific access (e.g. posting on behalf of a user), uploading media for a user etc.).
+**Steps**:
+1. In the developer portal, register your app with a redirect URI (e.g., `http://localhost:8080/callback`).
+2. Get Client ID (no secret needed for PKCE).
+3. Initiate the flow, direct user to auth URL and handle callback.
+**Example** (using a web server for callback):
+```python
+from xdk.auth import OAuth2PKCE
+from urllib.parse import urlparse
+import webbrowser
+# Step 1: Create PKCE instance
+auth = OAuth2PKCE(
+ client_id="your_client_id",
+ redirect_uri="http://localhost:8080/callback",
+ scopes=["tweet.read", "users.read", "offline.access"] # Adjust scopes as needed
+)
+# Step 2: Get authorization URL
+auth_url = auth.get_authorization_url()
+print(f"Visit this URL to authorize: {auth_url}")
+webbrowser.open(auth_url)
+# Step 3: Handle callback (in a real app, use a web framework like Flask)
+# Assume callback_url = "http://localhost:8080/callback?code=AUTH_CODE_HERE"
+callback_url = input("Paste the full callback URL here: ")
+parsed = urlparse(callback_url)
+code = parsed.query.split("=")[1]
+# Step 4: Exchange code for tokens
+tokens = auth.fetch_token(authorization_code=code)
+access_token = tokens["access_token"]
+refresh_token = tokens["refresh_token"] # Store for renewal
+# Step 5: Create client
+client = Client(oauth2_access_token=access_token)
+```
+**Token Refresh** (automatic in SDK for long-lived sessions):
+```python
+# If access token expires, refresh using stored refresh_token
+tokens = auth.refresh_token(refresh_token=refresh_token)
+client = Client(oauth2_access_token=tokens["access_token"])
+```
+### 3. OAuth 1.0a User Context
+For legacy endpoints that require OAuth 1.0 support.
+**Steps**:
+1. Generate Consumer Key/Secret and Access Token/Secret via Developer Portal.
+2. Pass it when initializing the client.
+**Example**:
+```python
+from xdk.auth import OAuth1User
+auth = OAuth1User(
+ consumer_key="your_consumer_key",
+ consumer_secret="your_consumer_secret",
+ access_token="your_access_token",
+ access_token_secret="your_access_token_secret"
+)
+client = Client(auth=auth)
+```
+**Note**:
+- Never hardcode secrets in production; use environment variables or secret managers (e.g., `os.getenv("X_BEARER_TOKEN")`).
+- For PKCE, ensure HTTPS for redirect URIs in production.
+- The SDK validates tokens and raises `xdk.AuthenticationError` on failures.
+"""
+ (output_dir / "xdks" / "python" / "authentication.mdx").write_text(auth_content)
+ # Pagination page
+ pagination_content = """---
+title: Pagination
+sidebarTitle: Pagination
+---
+The X API uses pagination for endpoints that return multiple pages of results (e.g. timelines, search etc.). Each API call response includes a `meta` object with `result_count`, `previous_token`, and `next_token`. The XDK takes care of making multiple API calls using the `next_token` so developers can just specify how much data they are looking for without having to make multiple calls.
+The SDK simplifies this with:
+- **Built-in Iterators**: Use generator functions for seamless multi-page fetching.
+- **Explicit Token Handling**: For flexible manual control when needed by passing `pagination_token` when needed.
+- **Max Results Enforcement**: Respect `max_results` per call (up to API limits, e.g., 100 for search).
+## Automatic Pagination (Recommended)
+Use the `iterate()` method on paginated responses to fetch all results lazily.
+**Example: Paginated Search**
+```python
+from xdk import Client
+client = Client(bearer_token="your_bearer_token")
+# Search with automatic pagination
+all_posts = []
+for page in client.posts.search_recent(
+ query="python",
+ max_results=100, # Per page
+ tweetfields=["created_at", "author_id"] # Optional expansions
+):
+ all_posts.extend(page.data)
+ print(f"Fetched {len(page.data)} Posts (total: {len(all_posts)})")
+print(f"Total tweets: {len(all_posts)}")
+```
+- The iterator handles `next_token` automatically.
+- Stops when no `next_token` is present.
+- Supports rate limit backoff to avoid 429 errors.
+## Manual Pagination
+If you require control over the results for some custom logic (e.g. processing page-by-page), you can still use the `next_token` and do the pagination manually as shown below:
+```python
+response = client.posts.search_recent(
+ query="xdk python sdk",
+ max_results=100,
+ pagination_token=None # First page
+)
+print(f"First page: {len(response.data)} Posts")
+next_token = response.meta.next_token
+if next_token:
+ next_response = client.posts.search_recent(
+ query="xdk python sdk",
+ max_results=100,
+ pagination_token=next_token
+ )
+ print(f"Second page: {len(next_response.data)} Posts")
+```
+**Tips**:
+- Always specify `max_results` to optimize (default varies by endpoint).
+- Monitor `meta.result_count` for debugging.
+- For very large queries, consider async iteration to avoid blocking.
+"""
+ (output_dir / "xdks" / "python" / "pagination.mdx").write_text(
+ pagination_content
+ )
+ # Streaming page
+ streaming_content = """---
+title: Streaming
+sidebarTitle: Streaming
+---
+The X API supports real-time data via endpoints like the [Filtered Stream Endpoint](https://docs.x.com/x-api/posts/filtered-stream/introduction), delivering matching Posts as they occur. This requires making a persistent http connection.
+## Setup and Basic Streaming
+### Synchronous
+```python
+from xdk import Client
+# Initialize client
+client = Client(bearer_token="your_bearer_token")
+# Stream posts (make sure you have rules set up first)
+for post_response in client.stream.posts():
+ data = post_response.model_dump()
+ if 'data' in data and data['data']:
+ tweet = data['data']
+ print(f"Post: {tweet.get('text', '')}")
+```
+### Async
+```python
+import asyncio
+from asyncio import Queue
+import threading
+from xdk import Client
+async def stream_posts_async(client: Client):
+ queue = Queue()
+ loop = asyncio.get_event_loop()
+ stop = threading.Event()
+ def run_stream():
+ for post in client.stream.posts():
+ if stop.is_set():
+ break
+ asyncio.run_coroutine_threadsafe(queue.put(post), loop)
+ asyncio.run_coroutine_threadsafe(queue.put(None), loop)
+ threading.Thread(target=run_stream, daemon=True).start()
+ while True:
+ post = await queue.get()
+ if post is None:
+ break
+ data = post.model_dump()
+ if 'data' in data and data['data']:
+ print(f"Post: {data['data'].get('text', '')}")
+ stop.set()
+async def main():
+ client = Client(bearer_token="your_bearer_token")
+ await stream_posts_async(client)
+asyncio.run(main())
+```
+## Rule Management
+Rules define filters on what specific data you are looking for(e.g. keywords, users etc). You can learn more about how to build rules using [this guide](https://docs.x.com/x-api/posts/filtered-stream/integrate/build-a-rule)
+**Adding Rules**:
+```python
+from xdk.stream.models import UpdateRulesRequest
+# Add a rule
+add_rules = {
+ "add": [
+ {"value": "from:xdevelopers", "tag": "official_updates"}
+ ]
+}
+request_body = UpdateRulesRequest(**add_rules)
+response = client.stream.update_rules(body=request_body)
+```
+**Deleting Rules**:
+```python
+from xdk.stream.models import UpdateRulesRequest
+delete_rules = {
+ "delete": {
+ "ids": ["rule_id_1", "rule_id_2"]
+ }
+}
+request_body = UpdateRulesRequest(**delete_rules)
+response = client.stream.update_rules(body=request_body)
+```
+**Listing Rules**:
+```python
+response = client.stream.get_rules()
+# Print rules
+for rule in response.data:
+ print(f"ID: {rule.id}, Value: {rule.value}, Tag: {rule.tag}")
+```
+For full rule syntax, see [X Streaming Rules Docs](https://developer.x.com/en/docs/twitter-api/tweets/filtered-stream/integrate/build-a-rule).
+## Troubleshooting
+- **403 Forbidden**: Invalid auth or insufficient permissions.
+- **420 Enhance Your Calm**: Rate limited; wait and retry.
+- **No Data**: Check rules with `get_rules()`; ensure matching Posts exist.
+For more examples and API reference, see the inline docstrings (e.g., `help(client.tweets.search_recent)`) or the generated stubs in the source. Contribute feedback via the [GitHub repo](https://github.com/xdevplatform/xdk/tree/main/xdk/python).
+"""
+ (output_dir / "xdks" / "python" / "streaming.mdx").write_text(streaming_content)
+ # Create navigation structure
+ print("⚙️ Creating navigation structure...")
+ # Build API Reference groups
+ ref_root = output_dir / "xdks" / "python" / "reference"
+ classes_dir = ref_root / "classes"
+ modules_dir = ref_root / "modules"
+ def list_files_no_ext(directory):
+ try:
+ return [
+ f"xdks/python/reference/{directory.name}/{f.stem}"
+ for f in directory.glob("*.mdx")
+ ]
+ except:
+ return []
+ classes_pages = list_files_no_ext(classes_dir) if classes_dir.exists() else []
+ modules_pages = list_files_no_ext(modules_dir) if modules_dir.exists() else []
+ # Group pages by module prefix
+ MODULE_PREFIXES = [
+ "AccountActivity",
+ "Activity",
+ "Communities",
+ "CommunityNotes",
+ "Compliance",
+ "Connections",
+ "DirectMessages",
+ "General",
+ "Lists",
+ "Media",
+ "Posts",
+ "Spaces",
+ "Stream",
+ "Trends",
+ "Usage",
+ "Users",
+ "Webhooks",
+ "Client",
+ "Paginator",
+ "OAuth2",
+ ]
+ def group_pages(pages, kind):
+ buckets = {}
+ for p in pages:
+ name = Path(p).stem
+ group = None
+ for pref in MODULE_PREFIXES:
+ if name.startswith(pref):
+ group = pref
+ break
+ if not group:
+ if kind == "classes":
+ if name.endswith("Client"):
+ group = "Clients"
+ elif "Stream" in name:
+ group = "Streaming"
+ elif "Paginator" in name:
+ group = "Pagination"
+ else:
+ group = "Core"
+ else:
+ group = "Misc"
+ if group not in buckets:
+ buckets[group] = []
+ buckets[group].append(p)
+ # Sort pages within groups
+ for group in buckets:
+ buckets[group].sort()
+ return [{"group": k, "pages": v} for k, v in sorted(buckets.items())]
+ class_groups = group_pages(classes_pages, "classes")
+ module_groups = group_pages(modules_pages, "modules")
+ # Process modules.md to create accordion structure
+ modules_md_path = docs_dir / "modules.md"
+ if modules_md_path.exists():
+ modules_raw = modules_md_path.read_text(encoding="utf-8")
+ # Extract title
+ title_match = re.search(r"^#\s+(.+)$", modules_raw, re.MULTILINE)
+ modules_title = title_match.group(1).strip() if title_match else "Modules"
+ # Parse the modules structure and convert to accordion
+ # Instead of parsing modules.md, use the actual reference files we have
+ # Group by package name from actual files
+ packages = {}
+ # Get all reference files
+ ref_root = output_dir / "xdks" / "python" / "reference"
+ all_ref_files = [
+ f for f in ref_root.glob("*.mdx") if f.stem not in ["modules", "index"]
+ ]
+ # Group files by package
+ for ref_file in all_ref_files:
+ name = ref_file.stem
+ # Extract package name
+ if ".client" in name:
+ package_name = name.replace("xdk.", "").replace(".client", "")
+ module_type = "Client"
+ elif ".models" in name:
+ package_name = name.replace("xdk.", "").replace(".models", "")
+ module_type = "Models"
+ else:
+ # Other modules like xdk.client, xdk.paginator
+ parts = name.replace("xdk.", "").split(".")
+ package_name = parts[0] if parts else "Core"
+ module_type = parts[-1].capitalize() if len(parts) > 1 else "Core"
+ # Convert to display name
+ package_display = " ".join(
+ word.capitalize() for word in package_name.split("_")
+ )
+ if package_display not in packages:
+ packages[package_display] = []
+ # Add module link
+ packages[package_display].append(
+ {"name": module_type, "link": f"xdks/python/reference/{name}"}
+ )
+ # Build accordion content
+ package_accordions = []
+ for package_name, modules in sorted(packages.items()):
+ if modules:
+ module_items = "\n".join(
+ [
+ f' - [{m["name"]}](/{m["link"]})'
+ for m in sorted(modules, key=lambda x: x["name"])
+ ]
+ )
+ package_accordions.append(
+ f' \n{module_items}\n '
+ )
+ # Build final modules content
+ if package_accordions:
+ modules_content = f"""---
+title: "{modules_title}"
+sidebarTitle: "{modules_title}"
+---
+
+
+{chr(10).join(package_accordions)}
+
+
+"""
+ else:
+ modules_content = f"""---
+title: "{modules_title}"
+sidebarTitle: "{modules_title}"
+---
+
+
+
+
+"""
+ # Write modules.mdx
+ (output_dir / "xdks" / "python" / "reference" / "modules.mdx").write_text(
+ modules_content, encoding="utf-8"
+ )
+ # Get all reference files for navigation
+ ref_root = output_dir / "xdks" / "python" / "reference"
+ all_ref_files = [
+ f
+ for f in ref_root.glob("*.mdx")
+ if f.stem != "modules" and f.stem != "index"
+ ]
+ # Separate into clients, models, and other
+ client_files = [f for f in all_ref_files if f.stem.endswith(".client")]
+ model_files = [f for f in all_ref_files if f.stem.endswith(".models")]
+ other_files = [
+ f
+ for f in all_ref_files
+ if not f.stem.endswith(".client") and not f.stem.endswith(".models")
+ ]
+ # Group by package
+ def group_by_package(files):
+ buckets = {}
+ for f in files:
+ name = f.stem
+ if ".client" in name:
+ package = name.replace("xdk.", "").replace(".client", "")
+ elif ".models" in name:
+ package = name.replace("xdk.", "").replace(".models", "")
+ else:
+ parts = name.replace("xdk.", "").split(".")
+ package = parts[0] if parts else "Core"
+ # Convert to display name
+ package_display = " ".join(
+ word.capitalize() for word in package.split("_")
+ )
+ if package_display not in buckets:
+ buckets[package_display] = []
+ buckets[package_display].append(f"xdks/python/reference/{f.stem}")
+ # Sort pages within groups
+ for group in buckets:
+ buckets[group].sort()
+ return [{"group": k, "pages": v} for k, v in sorted(buckets.items())]
+ client_groups = group_by_package(client_files)
+ model_groups = group_by_package(model_files)
+ other_groups = group_by_package(other_files)
+ # Generate navigation JSON
+ # Build navigation structure with packages and modules in sidebar
+ api_ref_pages = ["xdks/python/reference/modules"]
+ # Add client groups
+ if client_groups:
+ api_ref_pages.append({"group": "Clients", "pages": client_groups})
+ # Add model groups
+ if model_groups:
+ api_ref_pages.append({"group": "Models", "pages": model_groups})
+ # Add other groups
+ if other_groups:
+ api_ref_pages.append({"group": "Core", "pages": other_groups})
+ python_sdk_navigation = {
+ "tab": "Python SDK",
+ "hidden": True,
+ "pages": [
+ "xdks/python/overview",
+ "xdks/python/install",
+ "xdks/python/quickstart",
+ "xdks/python/authentication",
+ "xdks/python/pagination",
+ "xdks/python/streaming",
+ {"group": "API Reference", "pages": api_ref_pages},
+ ],
+ }
+ # Write navigation JSON
+ nav_json_path = output_dir / "python-sdk-navigation.json"
+ nav_json_path.write_text(json.dumps(python_sdk_navigation, indent=2))
+ print("✅ Python SDK documentation processed successfully!")
+ print(f"📁 Output directory: {output_dir}/")
+ print(f"📊 Processed {len(processed_files)} files")
+ print("\n🚀 Integration steps:")
+ print("1. Copy the 'xdks/' folder to your existing Mintlify site")
+ print(
+ "2. Add the navigation structure from 'python-sdk-navigation.json' to your mintlify.json"
+ )
+ print("3. Push to your main branch to deploy")
+ except Exception as error:
+ print(f"❌ Error processing documentation: {error}")
+ import traceback
+ traceback.print_exc()
+ sys.exit(1)
+
+
+ def list_files_no_ext(directory):
+ try:
+ return [
+ f"xdks/python/reference/{directory.name}/{f.stem}"
+ for f in directory.glob("*.mdx")
+ ]
+ except:
+ return []
+
+ classes_pages = list_files_no_ext(classes_dir) if classes_dir.exists() else []
+ modules_pages = list_files_no_ext(modules_dir) if modules_dir.exists() else []
+
+ # Group pages by module prefix
+ MODULE_PREFIXES = [
+ "AccountActivity",
+ "Activity",
+ "Communities",
+ "CommunityNotes",
+ "Compliance",
+ "Connections",
+ "DirectMessages",
+ "General",
+ "Lists",
+ "Media",
+ "Posts",
+ "Spaces",
+ "Stream",
+ "Trends",
+ "Usage",
+ "Users",
+ "Webhooks",
+ "Client",
+ "Paginator",
+ "OAuth2",
+ ]
+
+
+ def group_pages(pages, kind):
+ buckets = {}
+ for p in pages:
+ name = Path(p).stem
+ group = None
+ for pref in MODULE_PREFIXES:
+ if name.startswith(pref):
+ group = pref
+ break
+ if not group:
+ if kind == "classes":
+ if name.endswith("Client"):
+ group = "Clients"
+ elif "Stream" in name:
+ group = "Streaming"
+ elif "Paginator" in name:
+ group = "Pagination"
+ else:
+ group = "Core"
+ else:
+ group = "Misc"
+ if group not in buckets:
+ buckets[group] = []
+ buckets[group].append(p)
+ # Sort pages within groups
+ for group in buckets:
+ buckets[group].sort()
+ return [{"group": k, "pages": v} for k, v in sorted(buckets.items())]
+
+ class_groups = group_pages(classes_pages, "classes")
+ module_groups = group_pages(modules_pages, "modules")
+
+ # Process modules.md to create accordion structure
+ modules_md_path = docs_dir / "modules.md"
+ if modules_md_path.exists():
+ modules_raw = modules_md_path.read_text(encoding="utf-8")
+ # Extract title
+ title_match = re.search(r"^#\s+(.+)$", modules_raw, re.MULTILINE)
+ modules_title = title_match.group(1).strip() if title_match else "Modules"
+
+ # Parse the modules structure and convert to accordion
+ # Instead of parsing modules.md, use the actual reference files we have
+ # Group by package name from actual files
+ packages = {}
+
+ # Get all reference files
+ ref_root = output_dir / "xdks" / "python" / "reference"
+ all_ref_files = [
+ f for f in ref_root.glob("*.mdx") if f.stem not in ["modules", "index"]
+ ]
+
+ # Group files by package
+ for ref_file in all_ref_files:
+ name = ref_file.stem
+ # Extract package name
+ if ".client" in name:
+ package_name = name.replace("xdk.", "").replace(".client", "")
+ module_type = "Client"
+ elif ".models" in name:
+ package_name = name.replace("xdk.", "").replace(".models", "")
+ module_type = "Models"
+ else:
+ # Other modules like xdk.client, xdk.paginator
+ parts = name.replace("xdk.", "").split(".")
+ package_name = parts[0] if parts else "Core"
+ module_type = parts[-1].capitalize() if len(parts) > 1 else "Core"
+
+ # Convert to display name
+ package_display = " ".join(
+ word.capitalize() for word in package_name.split("_")
+ )
+
+ if package_display not in packages:
+ packages[package_display] = []
+
+ # Add module link
+ packages[package_display].append(
+ {"name": module_type, "link": f"xdks/python/reference/{name}"}
+ )
+
+ # Build accordion content
+ package_accordions = []
+ for package_name, modules in sorted(packages.items()):
+ if modules:
+ module_items = "\n".join(
+ [
+ f' - [{m["name"]}](/{m["link"]})'
+ for m in sorted(modules, key=lambda x: x["name"])
+ ]
+ )
+ package_accordions.append(
+ f' \n{module_items}\n '
+ )
+
+ # Build final modules content
+ if package_accordions:
+ modules_content = f"""---
+title: "{modules_title}"
+sidebarTitle: "{modules_title}"
+---
+
+
+
+
+
+{chr(10).join(package_accordions)}
+
+
+
+
+"""
+ else:
+ modules_content = f"""---
+title: "{modules_title}"
+sidebarTitle: "{modules_title}"
+---
+
+
+
+
+
+
+
+"""
+
+ # Write modules.mdx
+ (output_dir / "xdks" / "python" / "reference" / "modules.mdx").write_text(
+ modules_content, encoding="utf-8"
+ )
+
+ # Get all reference files for navigation
+ ref_root = output_dir / "xdks" / "python" / "reference"
+ all_ref_files = [
+ f
+ for f in ref_root.glob("*.mdx")
+ if f.stem != "modules" and f.stem != "index"
+ ]
+
+ # Separate into clients, models, and other
+ client_files = [f for f in all_ref_files if f.stem.endswith(".client")]
+ model_files = [f for f in all_ref_files if f.stem.endswith(".models")]
+ other_files = [
+ f
+ for f in all_ref_files
+ if not f.stem.endswith(".client") and not f.stem.endswith(".models")
+ ]
+
+ # Group by package
+
+
+ def group_by_package(files):
+ buckets = {}
+ for f in files:
+ name = f.stem
+ if ".client" in name:
+ package = name.replace("xdk.", "").replace(".client", "")
+ elif ".models" in name:
+ package = name.replace("xdk.", "").replace(".models", "")
+ else:
+ parts = name.replace("xdk.", "").split(".")
+ package = parts[0] if parts else "Core"
+ # Convert to display name
+ package_display = " ".join(
+ word.capitalize() for word in package.split("_")
+ )
+ if package_display not in buckets:
+ buckets[package_display] = []
+ buckets[package_display].append(f"xdks/python/reference/{f.stem}")
+ # Sort pages within groups
+ for group in buckets:
+ buckets[group].sort()
+ return [{"group": k, "pages": v} for k, v in sorted(buckets.items())]
+
+ client_groups = group_by_package(client_files)
+ model_groups = group_by_package(model_files)
+ other_groups = group_by_package(other_files)
+
+ # Generate navigation JSON
+ # Build navigation structure with packages and modules in sidebar
+ api_ref_pages = ["xdks/python/reference/modules"]
+
+ # Add client groups
+ if client_groups:
+ api_ref_pages.append({"group": "Clients", "pages": client_groups})
+
+ # Add model groups
+ if model_groups:
+ api_ref_pages.append({"group": "Models", "pages": model_groups})
+
+ # Add other groups
+ if other_groups:
+ api_ref_pages.append({"group": "Core", "pages": other_groups})
+
+ python_sdk_navigation = {
+ "tab": "Python SDK",
+ "hidden": True,
+ "pages": [
+ "xdks/python/overview",
+ "xdks/python/install",
+ "xdks/python/quickstart",
+ "xdks/python/authentication",
+ "xdks/python/pagination",
+ "xdks/python/streaming",
+ {"group": "API Reference", "pages": api_ref_pages},
+ ],
+ }
+
+ # Write navigation JSON
+ nav_json_path = output_dir / "python-sdk-navigation.json"
+ nav_json_path.write_text(json.dumps(python_sdk_navigation, indent=2))
+
+ print("✅ Python SDK documentation processed successfully!")
+ print(f"📁 Output directory: {output_dir}/")
+ print(f"📊 Processed {len(processed_files)} files")
+ print("\n🚀 Integration steps:")
+ print("1. Copy the 'xdks/' folder to your existing Mintlify site")
+ print(
+ "2. Add the navigation structure from 'python-sdk-navigation.json' to your mintlify.json"
+ )
+ print("3. Push to your main branch to deploy")
+
+ except Exception as error:
+ print(f"❌ Error processing documentation: {error}")
+ import traceback
+
+ traceback.print_exc()
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ process_docs()
diff --git a/xdk/python/scripts/watch-docs.py b/xdk/python/scripts/watch-docs.py
new file mode 100644
index 00000000..f580f03a
--- /dev/null
+++ b/xdk/python/scripts/watch-docs.py
@@ -0,0 +1,125 @@
+# AUTO-GENERATED FILE - DO NOT EDIT
+# This file was automatically generated by the XDK build tool.
+# Any manual changes will be overwritten on the next generation.
+#!/usr/bin/env python3
+"""
+AUTO-GENERATED FILE - DO NOT EDIT
+This file was automatically generated by the XDK build tool.
+Any manual changes will be overwritten on the next generation.
+
+Watch for changes and regenerate documentation automatically.
+"""
+
+import os
+import sys
+import time
+import subprocess
+from pathlib import Path
+from watchdog.observers import Observer
+from watchdog.events import FileSystemEventHandler
+
+print("🚀 Starting X API SDK Documentation Watch Server...")
+
+
+class DocsHandler(FileSystemEventHandler):
+ """Handle file system events for documentation regeneration."""
+
+
+ def __init__(self):
+ self.last_regeneration = 0
+ self.debounce_seconds = 2
+
+
+ def on_modified(self, event):
+ if event.is_directory:
+ return
+ # Only watch Python files
+ if not event.src_path.endswith(".py"):
+ return
+ # Skip if in docs or build directories
+ if "docs" in event.src_path or "__pycache__" in event.src_path:
+ return
+ # Debounce rapid changes
+ current_time = time.time()
+ if current_time - self.last_regeneration < self.debounce_seconds:
+ return
+ self.last_regeneration = current_time
+ print(f"📝 File changed: {event.src_path}")
+ regenerate_docs()
+
+
+def regenerate_docs():
+ """Regenerate documentation."""
+ print("🔄 Regenerating documentation...")
+ try:
+ result = subprocess.run(
+ [sys.executable, "scripts/generate-docs-simple.py"],
+ check=True,
+ capture_output=True,
+ text=True,
+ )
+ print(result.stdout)
+ print("✅ Documentation regenerated successfully")
+ except subprocess.CalledProcessError as e:
+ print(f"❌ Failed to regenerate documentation: {e}")
+ print(f"stderr: {e.stderr}")
+
+
+def start_server():
+ """Start a simple HTTP server for docs."""
+ try:
+ import http.server
+ import socketserver
+ import threading
+ PORT = 8080
+ Handler = http.server.SimpleHTTPRequestHandler
+ def run_server():
+ with socketserver.TCPServer(("", PORT), Handler) as httpd:
+ print(f"📚 Starting documentation server on http://localhost:{PORT}")
+ httpd.serve_forever()
+ server_thread = threading.Thread(target=run_server, daemon=True)
+ server_thread.start()
+ return server_thread
+ except Exception as e:
+ print(f"⚠️ Could not start HTTP server: {e}")
+ return None
+
+
+ def run_server():
+ with socketserver.TCPServer(("", PORT), Handler) as httpd:
+ print(f"📚 Starting documentation server on http://localhost:{PORT}")
+ httpd.serve_forever()
+
+ server_thread = threading.Thread(target=run_server, daemon=True)
+ server_thread.start()
+ return server_thread
+ except Exception as e:
+ print(f"⚠️ Could not start HTTP server: {e}")
+ return None
+
+
+# Initial documentation generation
+regenerate_docs()
+server_thread = start_server()
+
+# Watch for changes
+event_handler = DocsHandler()
+observer = Observer()
+
+# Watch xdk directory
+xdk_path = Path("xdk")
+if xdk_path.exists():
+ observer.schedule(event_handler, str(xdk_path), recursive=True)
+ observer.start()
+ print("👀 Watching for changes... Press Ctrl+C to stop")
+
+ try:
+ while True:
+ time.sleep(1)
+ except KeyboardInterrupt:
+ print("\n🛑 Shutting down documentation server...")
+ observer.stop()
+
+ observer.join()
+else:
+ print("⚠️ xdk directory not found")
diff --git a/xdk/python/tests/account_activity/test_contracts.py b/xdk/python/tests/account_activity/test_contracts.py
index 6932e06f..4dd1ff11 100644
--- a/xdk/python/tests/account_activity/test_contracts.py
+++ b/xdk/python/tests/account_activity/test_contracts.py
@@ -27,8 +27,8 @@ def setup_class(self):
self.account_activity_client = getattr(self.client, "account_activity")
- def test_validate_subscription_request_structure(self):
- """Test validate_subscription 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()
@@ -37,15 +37,16 @@ def test_validate_subscription_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, "validate_subscription")
+ method = getattr(self.account_activity_client, "delete_subscription")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -64,7 +65,7 @@ def test_validate_subscription_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.delete.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -73,16 +74,14 @@ def test_validate_subscription_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/webhooks/{webhook_id}/subscriptions/all"
- )
+ expected_path = "/2/account_activity/webhooks/{webhook_id}/subscriptions/{user_id}/all"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -98,12 +97,12 @@ def test_validate_subscription_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for validate_subscription: {e}")
+ pytest.fail(f"Contract test failed for delete_subscription: {e}")
- def test_validate_subscription_required_parameters(self):
- """Test that validate_subscription handles parameters correctly."""
- method = getattr(self.account_activity_client, "validate_subscription")
+ 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)
@@ -111,14 +110,14 @@ def test_validate_subscription_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_validate_subscription_response_structure(self):
- """Test validate_subscription 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 = {
@@ -128,13 +127,14 @@ def test_validate_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.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, "validate_subscription")
+ 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
@@ -146,8 +146,8 @@ def test_validate_subscription_response_structure(self):
)
- def test_create_subscription_request_structure(self):
- """Test create_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()
@@ -156,19 +156,14 @@ def test_create_subscription_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["webhook_id"] = "test_value"
# Add request body if required
- # Import and create proper request model instance
- from xdk.account_activity.models import CreateSubscriptionRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = CreateSubscriptionRequest()
# Call the method
try:
- method = getattr(self.account_activity_client, "create_subscription")
+ method = getattr(self.account_activity_client, "get_subscription_count")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -187,7 +182,7 @@ def test_create_subscription_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -196,16 +191,14 @@ def test_create_subscription_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/account_activity/webhooks/{webhook_id}/subscriptions/all"
- )
+ expected_path = "/2/account_activity/subscriptions/count"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -221,27 +214,27 @@ def test_create_subscription_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for create_subscription: {e}")
+ pytest.fail(f"Contract test failed for get_subscription_count: {e}")
- def test_create_subscription_required_parameters(self):
- """Test that create_subscription handles parameters correctly."""
- method = getattr(self.account_activity_client, "create_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.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_subscription_response_structure(self):
- """Test create_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 = {
@@ -251,17 +244,12 @@ def test_create_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.post.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
- # Import and create proper request model instance
- from xdk.account_activity.models import CreateSubscriptionRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = CreateSubscriptionRequest()
# Call method and verify response structure
- method = getattr(self.account_activity_client, "create_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
@@ -273,8 +261,8 @@ def test_create_subscription_response_structure(self):
)
- def test_delete_subscription_request_structure(self):
- """Test delete_subscription 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()
@@ -283,16 +271,17 @@ def test_delete_subscription_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"
- kwargs["user_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, "delete_subscription")
+ method = getattr(self.account_activity_client, "create_replay_job")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -311,7 +300,7 @@ def test_delete_subscription_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.delete.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -320,14 +309,16 @@ def test_delete_subscription_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/account_activity/webhooks/{webhook_id}/subscriptions/{user_id}/all"
+ expected_path = (
+ "/2/account_activity/replay/webhooks/{webhook_id}/subscriptions/all"
+ )
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -343,12 +334,12 @@ def test_delete_subscription_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for delete_subscription: {e}")
+ pytest.fail(f"Contract test failed for create_replay_job: {e}")
- def test_delete_subscription_required_parameters(self):
- """Test that delete_subscription handles parameters correctly."""
- method = getattr(self.account_activity_client, "delete_subscription")
+ 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)
@@ -356,14 +347,14 @@ def test_delete_subscription_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_subscription_response_structure(self):
- """Test delete_subscription 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 = {
@@ -373,14 +364,15 @@ def test_delete_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.post.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
kwargs["webhook_id"] = "test"
- kwargs["user_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, "delete_subscription")
+ 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
@@ -392,8 +384,8 @@ def test_delete_subscription_response_structure(self):
)
- def test_get_subscriptions_request_structure(self):
- """Test get_subscriptions 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()
@@ -410,7 +402,7 @@ def test_get_subscriptions_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.account_activity_client, "get_subscriptions")
+ method = getattr(self.account_activity_client, "validate_subscription")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -446,7 +438,7 @@ def test_get_subscriptions_request_structure(self):
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"
+ "/2/account_activity/webhooks/{webhook_id}/subscriptions/all"
)
assert expected_path.replace("{", "").replace(
"}", ""
@@ -463,12 +455,12 @@ def test_get_subscriptions_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_subscriptions: {e}")
+ pytest.fail(f"Contract test failed for validate_subscription: {e}")
- def test_get_subscriptions_required_parameters(self):
- """Test that get_subscriptions handles parameters correctly."""
- method = getattr(self.account_activity_client, "get_subscriptions")
+ 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)
@@ -482,8 +474,8 @@ def test_get_subscriptions_required_parameters(self):
method()
- def test_get_subscriptions_response_structure(self):
- """Test get_subscriptions 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 = {
@@ -499,7 +491,7 @@ def test_get_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_subscriptions")
+ 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
@@ -511,8 +503,8 @@ def test_get_subscriptions_response_structure(self):
)
- def test_create_replay_job_request_structure(self):
- """Test create_replay_job request structure."""
+ def test_create_subscription_request_structure(self):
+ """Test create_subscription request structure."""
# Mock the session to capture request details
with patch.object(self.client, "session") as mock_session:
mock_response = Mock()
@@ -526,12 +518,14 @@ def test_create_replay_job_request_structure(self):
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
+ # Import and create proper request model instance
+ from xdk.account_activity.models import CreateSubscriptionRequest
+ # Create instance with minimal valid data (empty instance should work for most cases)
+ kwargs["body"] = CreateSubscriptionRequest()
# Call the method
try:
- method = getattr(self.account_activity_client, "create_replay_job")
+ method = getattr(self.account_activity_client, "create_subscription")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -567,7 +561,7 @@ def test_create_replay_job_request_structure(self):
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"
+ "/2/account_activity/webhooks/{webhook_id}/subscriptions/all"
)
assert expected_path.replace("{", "").replace(
"}", ""
@@ -584,12 +578,12 @@ def test_create_replay_job_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for create_replay_job: {e}")
+ pytest.fail(f"Contract test failed for create_subscription: {e}")
- 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")
+ def test_create_subscription_required_parameters(self):
+ """Test that create_subscription handles parameters correctly."""
+ method = getattr(self.account_activity_client, "create_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)
@@ -603,8 +597,8 @@ def test_create_replay_job_required_parameters(self):
method()
- def test_create_replay_job_response_structure(self):
- """Test create_replay_job response structure validation."""
+ def test_create_subscription_response_structure(self):
+ """Test create_subscription response structure validation."""
with patch.object(self.client, "session") as mock_session:
# Create mock response with expected structure
mock_response_data = {
@@ -618,11 +612,13 @@ def test_create_replay_job_response_structure(self):
# Prepare minimal valid parameters
kwargs = {}
kwargs["webhook_id"] = "test"
- kwargs["from_date"] = "test_value"
- kwargs["to_date"] = "test_value"
# Add request body if required
+ # Import and create proper request model instance
+ from xdk.account_activity.models import CreateSubscriptionRequest
+ # Create instance with minimal valid data (empty instance should work for most cases)
+ kwargs["body"] = CreateSubscriptionRequest()
# Call method and verify response structure
- method = getattr(self.account_activity_client, "create_replay_job")
+ method = getattr(self.account_activity_client, "create_subscription")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -634,8 +630,8 @@ def test_create_replay_job_response_structure(self):
)
- def test_get_subscription_count_request_structure(self):
- """Test get_subscription_count 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()
@@ -648,10 +644,11 @@ def test_get_subscription_count_request_structure(self):
# 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_subscription_count")
+ method = getattr(self.account_activity_client, "get_subscriptions")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -686,7 +683,9 @@ def test_get_subscription_count_request_structure(self):
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/all/list"
+ )
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -702,27 +701,27 @@ def test_get_subscription_count_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_subscription_count: {e}")
+ pytest.fail(f"Contract test failed for get_subscriptions: {e}")
- 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
+ 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)
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_subscription_count_response_structure(self):
- """Test get_subscription_count 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 = {
@@ -735,9 +734,10 @@ def test_get_subscription_count_response_structure(self):
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_subscription_count")
+ 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
diff --git a/xdk/python/tests/account_activity/test_structure.py b/xdk/python/tests/account_activity/test_structure.py
index 4bc5323c..5bcd8215 100644
--- a/xdk/python/tests/account_activity/test_structure.py
+++ b/xdk/python/tests/account_activity/test_structure.py
@@ -28,33 +28,34 @@ def setup_class(self):
self.account_activity_client = getattr(self.client, "account_activity")
- def test_validate_subscription_exists(self):
- """Test that validate_subscription 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, "validate_subscription", None)
+ method = getattr(AccountActivityClient, "delete_subscription", None)
assert (
method is not None
- ), f"Method validate_subscription does not exist on AccountActivityClient"
+ ), f"Method delete_subscription does not exist on AccountActivityClient"
# Check method is callable
- assert callable(method), f"validate_subscription 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"validate_subscription 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 = [
"webhook_id",
+ "user_id",
]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from validate_subscription"
+ ), f"Required parameter '{required_param}' missing from delete_subscription"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -65,43 +66,41 @@ def test_validate_subscription_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_validate_subscription_return_annotation(self):
- """Test that validate_subscription has proper return type annotation."""
- method = getattr(AccountActivityClient, "validate_subscription")
+ 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 validate_subscription should have return type annotation"
+ ), f"Method delete_subscription should have return type annotation"
- def test_create_subscription_exists(self):
- """Test that create_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, "create_subscription", None)
+ method = getattr(AccountActivityClient, "get_subscription_count", None)
assert (
method is not None
- ), f"Method create_subscription does not exist on AccountActivityClient"
+ ), f"Method get_subscription_count does not exist on AccountActivityClient"
# Check method is callable
- assert callable(method), f"create_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"create_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",
- ]
+ required_params = []
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from create_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:
@@ -112,44 +111,45 @@ def test_create_subscription_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_create_subscription_return_annotation(self):
- """Test that create_subscription has proper return type annotation."""
- method = getattr(AccountActivityClient, "create_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 create_subscription should have return type annotation"
+ ), f"Method get_subscription_count should have return type annotation"
- def test_delete_subscription_exists(self):
- """Test that delete_subscription 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, "delete_subscription", None)
+ method = getattr(AccountActivityClient, "create_replay_job", None)
assert (
method is not None
- ), f"Method delete_subscription does not exist on AccountActivityClient"
+ ), f"Method create_replay_job does not exist on AccountActivityClient"
# Check method is callable
- assert callable(method), f"delete_subscription 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"delete_subscription 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]}'"
# Check required parameters exist (excluding 'self')
required_params = [
"webhook_id",
- "user_id",
+ "from_date",
+ "to_date",
]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from delete_subscription"
+ ), 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:
@@ -160,32 +160,32 @@ def test_delete_subscription_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_delete_subscription_return_annotation(self):
- """Test that delete_subscription has proper return type annotation."""
- method = getattr(AccountActivityClient, "delete_subscription")
+ 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 delete_subscription should have return type annotation"
+ ), f"Method create_replay_job should have return type annotation"
- def test_get_subscriptions_exists(self):
- """Test that get_subscriptions 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, "get_subscriptions", None)
+ method = getattr(AccountActivityClient, "validate_subscription", None)
assert (
method is not None
- ), f"Method get_subscriptions does not exist on AccountActivityClient"
+ ), f"Method validate_subscription does not exist on AccountActivityClient"
# Check method is callable
- assert callable(method), f"get_subscriptions 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"get_subscriptions 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]}'"
@@ -196,7 +196,7 @@ def test_get_subscriptions_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_subscriptions"
+ ), f"Required parameter '{required_param}' missing from validate_subscription"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -207,45 +207,43 @@ def test_get_subscriptions_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_subscriptions_return_annotation(self):
- """Test that get_subscriptions has proper return type annotation."""
- method = getattr(AccountActivityClient, "get_subscriptions")
+ 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 get_subscriptions should have return type annotation"
+ ), f"Method validate_subscription should have return type annotation"
- def test_create_replay_job_exists(self):
- """Test that create_replay_job method exists with correct signature."""
+ def test_create_subscription_exists(self):
+ """Test that create_subscription method exists with correct signature."""
# Check method exists
- method = getattr(AccountActivityClient, "create_replay_job", None)
+ method = getattr(AccountActivityClient, "create_subscription", None)
assert (
method is not None
- ), f"Method create_replay_job does not exist on AccountActivityClient"
+ ), f"Method create_subscription does not exist on AccountActivityClient"
# Check method is callable
- assert callable(method), f"create_replay_job is not callable"
+ assert callable(method), f"create_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_replay_job should have at least 'self' parameter"
+ ), f"create_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",
- "from_date",
- "to_date",
]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from create_replay_job"
+ ), f"Required parameter '{required_param}' missing from create_subscription"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -256,41 +254,43 @@ def test_create_replay_job_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_create_replay_job_return_annotation(self):
- """Test that create_replay_job has proper return type annotation."""
- method = getattr(AccountActivityClient, "create_replay_job")
+ def test_create_subscription_return_annotation(self):
+ """Test that create_subscription has proper return type annotation."""
+ method = getattr(AccountActivityClient, "create_subscription")
sig = inspect.signature(method)
# Check return annotation exists
assert (
sig.return_annotation is not inspect.Signature.empty
- ), f"Method create_replay_job should have return type annotation"
+ ), f"Method create_subscription should have return type annotation"
- def test_get_subscription_count_exists(self):
- """Test that get_subscription_count 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_subscription_count", None)
+ method = getattr(AccountActivityClient, "get_subscriptions", None)
assert (
method is not None
- ), f"Method get_subscription_count does not exist on AccountActivityClient"
+ ), f"Method get_subscriptions does not exist on AccountActivityClient"
# Check method is callable
- assert callable(method), f"get_subscription_count 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_subscription_count 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]}'"
# 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_subscription_count"
+ ), f"Required parameter '{required_param}' missing from get_subscriptions"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -301,25 +301,25 @@ def test_get_subscription_count_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_subscription_count_return_annotation(self):
- """Test that get_subscription_count has proper return type annotation."""
- method = getattr(AccountActivityClient, "get_subscription_count")
+ 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_subscription_count should have return type annotation"
+ ), f"Method get_subscriptions should have return type annotation"
def test_all_expected_methods_exist(self):
"""Test that all expected methods exist on the client."""
expected_methods = [
+ "delete_subscription",
+ "get_subscription_count",
+ "create_replay_job",
"validate_subscription",
"create_subscription",
- "delete_subscription",
"get_subscriptions",
- "create_replay_job",
- "get_subscription_count",
]
for expected_method in expected_methods:
assert hasattr(
diff --git a/xdk/python/tests/activity/test_contracts.py b/xdk/python/tests/activity/test_contracts.py
index 3658ccd6..bfd27472 100644
--- a/xdk/python/tests/activity/test_contracts.py
+++ b/xdk/python/tests/activity/test_contracts.py
@@ -142,8 +142,8 @@ def test_stream_response_structure(self):
)
- def test_get_subscriptions_request_structure(self):
- """Test get_subscriptions request structure."""
+ def test_update_subscription_request_structure(self):
+ """Test update_subscription request structure."""
# Mock the session to capture request details
with patch.object(self.client, "session") as mock_session:
mock_response = Mock()
@@ -152,14 +152,19 @@ def test_get_subscriptions_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["subscription_id"] = "test_value"
# Add request body if required
+ # Import and create proper request model instance
+ from xdk.activity.models import UpdateSubscriptionRequest
+ # Create instance with minimal valid data (empty instance should work for most cases)
+ kwargs["body"] = UpdateSubscriptionRequest()
# Call the method
try:
- method = getattr(self.activity_client, "get_subscriptions")
+ method = getattr(self.activity_client, "update_subscription")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -178,7 +183,7 @@ def test_get_subscriptions_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.put.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -187,14 +192,14 @@ def test_get_subscriptions_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/activity/subscriptions"
+ expected_path = "/2/activity/subscriptions/{subscription_id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -210,27 +215,27 @@ def test_get_subscriptions_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_subscriptions: {e}")
+ pytest.fail(f"Contract test failed for update_subscription: {e}")
- def test_get_subscriptions_required_parameters(self):
- """Test that get_subscriptions handles parameters correctly."""
- method = getattr(self.activity_client, "get_subscriptions")
- # No required parameters, method should be callable without args
+ def test_update_subscription_required_parameters(self):
+ """Test that update_subscription handles parameters correctly."""
+ method = getattr(self.activity_client, "update_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.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_subscriptions_response_structure(self):
- """Test get_subscriptions response structure validation."""
+ def test_update_subscription_response_structure(self):
+ """Test update_subscription response structure validation."""
with patch.object(self.client, "session") as mock_session:
# Create mock response with expected structure
mock_response_data = {
@@ -240,12 +245,17 @@ def test_get_subscriptions_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["subscription_id"] = "test"
# Add request body if required
+ # Import and create proper request model instance
+ from xdk.activity.models import UpdateSubscriptionRequest
+ # Create instance with minimal valid data (empty instance should work for most cases)
+ kwargs["body"] = UpdateSubscriptionRequest()
# Call method and verify response structure
- method = getattr(self.activity_client, "get_subscriptions")
+ method = getattr(self.activity_client, "update_subscription")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -257,8 +267,8 @@ def test_get_subscriptions_response_structure(self):
)
- def test_create_subscription_request_structure(self):
- """Test create_subscription 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()
@@ -267,18 +277,15 @@ def test_create_subscription_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["subscription_id"] = "test_value"
# Add request body if required
- # Import and create proper request model instance
- from xdk.activity.models import CreateSubscriptionRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = CreateSubscriptionRequest()
# Call the method
try:
- method = getattr(self.activity_client, "create_subscription")
+ method = getattr(self.activity_client, "delete_subscription")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -297,7 +304,7 @@ def test_create_subscription_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.delete.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -306,14 +313,14 @@ def test_create_subscription_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/activity/subscriptions"
+ expected_path = "/2/activity/subscriptions/{subscription_id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -329,12 +336,12 @@ def test_create_subscription_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for create_subscription: {e}")
+ pytest.fail(f"Contract test failed for delete_subscription: {e}")
- def test_create_subscription_required_parameters(self):
- """Test that create_subscription handles parameters correctly."""
- method = getattr(self.activity_client, "create_subscription")
+ def test_delete_subscription_required_parameters(self):
+ """Test that delete_subscription handles parameters correctly."""
+ method = getattr(self.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)
@@ -342,14 +349,14 @@ def test_create_subscription_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_subscription_response_structure(self):
- """Test create_subscription 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 = {
@@ -359,16 +366,13 @@ def test_create_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.post.return_value = mock_response
+ mock_session.delete.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
+ kwargs["subscription_id"] = "test"
# Add request body if required
- # Import and create proper request model instance
- from xdk.activity.models import CreateSubscriptionRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = CreateSubscriptionRequest()
# Call method and verify response structure
- method = getattr(self.activity_client, "create_subscription")
+ method = getattr(self.activity_client, "delete_subscription")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -380,8 +384,8 @@ def test_create_subscription_response_structure(self):
)
- def test_update_subscription_request_structure(self):
- """Test update_subscription 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()
@@ -390,19 +394,14 @@ def test_update_subscription_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["subscription_id"] = "test_value"
# Add request body if required
- # Import and create proper request model instance
- from xdk.activity.models import UpdateSubscriptionRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = UpdateSubscriptionRequest()
# Call the method
try:
- method = getattr(self.activity_client, "update_subscription")
+ method = getattr(self.activity_client, "get_subscriptions")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -421,7 +420,7 @@ def test_update_subscription_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.put.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -430,14 +429,14 @@ def test_update_subscription_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/activity/subscriptions/{subscription_id}"
+ expected_path = "/2/activity/subscriptions"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -453,27 +452,27 @@ def test_update_subscription_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for update_subscription: {e}")
+ pytest.fail(f"Contract test failed for get_subscriptions: {e}")
- def test_update_subscription_required_parameters(self):
- """Test that update_subscription handles parameters correctly."""
- method = getattr(self.activity_client, "update_subscription")
- # Test with missing required parameters - mock the request to avoid network calls
+ def test_get_subscriptions_required_parameters(self):
+ """Test that get_subscriptions handles parameters correctly."""
+ method = getattr(self.activity_client, "get_subscriptions")
+ # 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_update_subscription_response_structure(self):
- """Test update_subscription 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 = {
@@ -483,17 +482,12 @@ def test_update_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.put.return_value = mock_response
+ mock_session.get.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
- kwargs["subscription_id"] = "test"
# Add request body if required
- # Import and create proper request model instance
- from xdk.activity.models import UpdateSubscriptionRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = UpdateSubscriptionRequest()
# Call method and verify response structure
- method = getattr(self.activity_client, "update_subscription")
+ method = getattr(self.activity_client, "get_subscriptions")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -505,8 +499,8 @@ def test_update_subscription_response_structure(self):
)
- def test_delete_subscription_request_structure(self):
- """Test delete_subscription request structure."""
+ def test_create_subscription_request_structure(self):
+ """Test create_subscription request structure."""
# Mock the session to capture request details
with patch.object(self.client, "session") as mock_session:
mock_response = Mock()
@@ -515,15 +509,18 @@ def test_delete_subscription_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["subscription_id"] = "test_value"
# Add request body if required
+ # Import and create proper request model instance
+ from xdk.activity.models import CreateSubscriptionRequest
+ # Create instance with minimal valid data (empty instance should work for most cases)
+ kwargs["body"] = CreateSubscriptionRequest()
# Call the method
try:
- method = getattr(self.activity_client, "delete_subscription")
+ method = getattr(self.activity_client, "create_subscription")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -542,7 +539,7 @@ def test_delete_subscription_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.delete.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -551,14 +548,14 @@ def test_delete_subscription_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/activity/subscriptions/{subscription_id}"
+ expected_path = "/2/activity/subscriptions"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -574,12 +571,12 @@ def test_delete_subscription_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for delete_subscription: {e}")
+ pytest.fail(f"Contract test failed for create_subscription: {e}")
- def test_delete_subscription_required_parameters(self):
- """Test that delete_subscription handles parameters correctly."""
- method = getattr(self.activity_client, "delete_subscription")
+ def test_create_subscription_required_parameters(self):
+ """Test that create_subscription handles parameters correctly."""
+ method = getattr(self.activity_client, "create_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)
@@ -587,14 +584,14 @@ def test_delete_subscription_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_subscription_response_structure(self):
- """Test delete_subscription response structure validation."""
+ def test_create_subscription_response_structure(self):
+ """Test create_subscription response structure validation."""
with patch.object(self.client, "session") as mock_session:
# Create mock response with expected structure
mock_response_data = {
@@ -604,13 +601,16 @@ def test_delete_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.post.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
- kwargs["subscription_id"] = "test"
# Add request body if required
+ # Import and create proper request model instance
+ from xdk.activity.models import CreateSubscriptionRequest
+ # Create instance with minimal valid data (empty instance should work for most cases)
+ kwargs["body"] = CreateSubscriptionRequest()
# Call method and verify response structure
- method = getattr(self.activity_client, "delete_subscription")
+ method = getattr(self.activity_client, "create_subscription")
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/activity/test_structure.py b/xdk/python/tests/activity/test_structure.py
index 3a8e58f4..d507d30c 100644
--- a/xdk/python/tests/activity/test_structure.py
+++ b/xdk/python/tests/activity/test_structure.py
@@ -73,31 +73,33 @@ def test_stream_return_annotation(self):
), f"Method stream should have return type annotation"
- def test_get_subscriptions_exists(self):
- """Test that get_subscriptions method exists with correct signature."""
+ def test_update_subscription_exists(self):
+ """Test that update_subscription method exists with correct signature."""
# Check method exists
- method = getattr(ActivityClient, "get_subscriptions", None)
+ method = getattr(ActivityClient, "update_subscription", None)
assert (
method is not None
- ), f"Method get_subscriptions does not exist on ActivityClient"
+ ), f"Method update_subscription does not exist on ActivityClient"
# Check method is callable
- assert callable(method), f"get_subscriptions is not callable"
+ assert callable(method), f"update_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_subscriptions should have at least 'self' parameter"
+ ), f"update_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 = [
+ "subscription_id",
+ ]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_subscriptions"
+ ), f"Required parameter '{required_param}' missing from update_subscription"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -108,41 +110,43 @@ def test_get_subscriptions_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_subscriptions_return_annotation(self):
- """Test that get_subscriptions has proper return type annotation."""
- method = getattr(ActivityClient, "get_subscriptions")
+ def test_update_subscription_return_annotation(self):
+ """Test that update_subscription has proper return type annotation."""
+ method = getattr(ActivityClient, "update_subscription")
sig = inspect.signature(method)
# Check return annotation exists
assert (
sig.return_annotation is not inspect.Signature.empty
- ), f"Method get_subscriptions should have return type annotation"
+ ), f"Method update_subscription should have return type annotation"
- def test_create_subscription_exists(self):
- """Test that create_subscription 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(ActivityClient, "create_subscription", None)
+ method = getattr(ActivityClient, "delete_subscription", None)
assert (
method is not None
- ), f"Method create_subscription does not exist on ActivityClient"
+ ), f"Method delete_subscription does not exist on ActivityClient"
# Check method is callable
- assert callable(method), f"create_subscription 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"create_subscription 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 = [
+ "subscription_id",
+ ]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from create_subscription"
+ ), f"Required parameter '{required_param}' missing from delete_subscription"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -153,43 +157,41 @@ def test_create_subscription_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_create_subscription_return_annotation(self):
- """Test that create_subscription has proper return type annotation."""
- method = getattr(ActivityClient, "create_subscription")
+ def test_delete_subscription_return_annotation(self):
+ """Test that delete_subscription has proper return type annotation."""
+ method = getattr(ActivityClient, "delete_subscription")
sig = inspect.signature(method)
# Check return annotation exists
assert (
sig.return_annotation is not inspect.Signature.empty
- ), f"Method create_subscription should have return type annotation"
+ ), f"Method delete_subscription should have return type annotation"
- def test_update_subscription_exists(self):
- """Test that update_subscription 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(ActivityClient, "update_subscription", None)
+ method = getattr(ActivityClient, "get_subscriptions", None)
assert (
method is not None
- ), f"Method update_subscription does not exist on ActivityClient"
+ ), f"Method get_subscriptions does not exist on ActivityClient"
# Check method is callable
- assert callable(method), f"update_subscription 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"update_subscription 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]}'"
# Check required parameters exist (excluding 'self')
- required_params = [
- "subscription_id",
- ]
+ required_params = []
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from update_subscription"
+ ), f"Required parameter '{required_param}' missing from get_subscriptions"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -200,43 +202,41 @@ def test_update_subscription_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_update_subscription_return_annotation(self):
- """Test that update_subscription has proper return type annotation."""
- method = getattr(ActivityClient, "update_subscription")
+ def test_get_subscriptions_return_annotation(self):
+ """Test that get_subscriptions has proper return type annotation."""
+ method = getattr(ActivityClient, "get_subscriptions")
sig = inspect.signature(method)
# Check return annotation exists
assert (
sig.return_annotation is not inspect.Signature.empty
- ), f"Method update_subscription should have return type annotation"
+ ), f"Method get_subscriptions should have return type annotation"
- def test_delete_subscription_exists(self):
- """Test that delete_subscription method exists with correct signature."""
+ def test_create_subscription_exists(self):
+ """Test that create_subscription method exists with correct signature."""
# Check method exists
- method = getattr(ActivityClient, "delete_subscription", None)
+ method = getattr(ActivityClient, "create_subscription", None)
assert (
method is not None
- ), f"Method delete_subscription does not exist on ActivityClient"
+ ), f"Method create_subscription does not exist on ActivityClient"
# Check method is callable
- assert callable(method), f"delete_subscription is not callable"
+ assert callable(method), f"create_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_subscription should have at least 'self' parameter"
+ ), f"create_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 = [
- "subscription_id",
- ]
+ required_params = []
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from delete_subscription"
+ ), f"Required parameter '{required_param}' missing from create_subscription"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -247,24 +247,24 @@ def test_delete_subscription_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_delete_subscription_return_annotation(self):
- """Test that delete_subscription has proper return type annotation."""
- method = getattr(ActivityClient, "delete_subscription")
+ def test_create_subscription_return_annotation(self):
+ """Test that create_subscription has proper return type annotation."""
+ method = getattr(ActivityClient, "create_subscription")
sig = inspect.signature(method)
# Check return annotation exists
assert (
sig.return_annotation is not inspect.Signature.empty
- ), f"Method delete_subscription should have return type annotation"
+ ), f"Method create_subscription should have return type annotation"
def test_all_expected_methods_exist(self):
"""Test that all expected methods exist on the client."""
expected_methods = [
"stream",
- "get_subscriptions",
- "create_subscription",
"update_subscription",
"delete_subscription",
+ "get_subscriptions",
+ "create_subscription",
]
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 f0779e21..418e7bd4 100644
--- a/xdk/python/tests/community_notes/test_contracts.py
+++ b/xdk/python/tests/community_notes/test_contracts.py
@@ -261,8 +261,8 @@ def test_delete_response_structure(self):
)
- def test_evaluate_request_structure(self):
- """Test evaluate 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()
@@ -271,18 +271,15 @@ def test_evaluate_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 EvaluateRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = EvaluateRequest()
# Call the method
try:
- method = getattr(self.community_notes_client, "evaluate")
+ method = getattr(self.community_notes_client, "search_written")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -301,7 +298,7 @@ def test_evaluate_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -310,14 +307,14 @@ def test_evaluate_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/evaluate_note"
+ expected_path = "/2/notes/search/notes_written"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -333,12 +330,12 @@ def test_evaluate_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for evaluate: {e}")
+ pytest.fail(f"Contract test failed for search_written: {e}")
- def test_evaluate_required_parameters(self):
- """Test that evaluate handles parameters correctly."""
- method = getattr(self.community_notes_client, "evaluate")
+ 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)
@@ -346,14 +343,14 @@ def test_evaluate_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_evaluate_response_structure(self):
- """Test evaluate 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 = {
@@ -363,16 +360,13 @@ def test_evaluate_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 EvaluateRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = EvaluateRequest()
# Call method and verify response structure
- method = getattr(self.community_notes_client, "evaluate")
+ 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
@@ -507,8 +501,8 @@ def test_create_response_structure(self):
)
- def test_search_written_request_structure(self):
- """Test search_written request structure."""
+ def test_evaluate_request_structure(self):
+ """Test evaluate request structure."""
# Mock the session to capture request details
with patch.object(self.client, "session") as mock_session:
mock_response = Mock()
@@ -517,15 +511,18 @@ def test_search_written_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["test_mode"] = True
# Add request body if required
+ # Import and create proper request model instance
+ from xdk.community_notes.models import EvaluateRequest
+ # Create instance with minimal valid data (empty instance should work for most cases)
+ kwargs["body"] = EvaluateRequest()
# Call the method
try:
- method = getattr(self.community_notes_client, "search_written")
+ method = getattr(self.community_notes_client, "evaluate")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -544,7 +541,7 @@ def test_search_written_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -553,14 +550,14 @@ def test_search_written_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/notes/search/notes_written"
+ expected_path = "/2/evaluate_note"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -576,12 +573,12 @@ def test_search_written_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for search_written: {e}")
+ pytest.fail(f"Contract test failed for evaluate: {e}")
- def test_search_written_required_parameters(self):
- """Test that search_written handles parameters correctly."""
- method = getattr(self.community_notes_client, "search_written")
+ def test_evaluate_required_parameters(self):
+ """Test that evaluate handles parameters correctly."""
+ method = getattr(self.community_notes_client, "evaluate")
# 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)
@@ -589,14 +586,14 @@ def test_search_written_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_search_written_response_structure(self):
- """Test search_written response structure validation."""
+ def test_evaluate_response_structure(self):
+ """Test evaluate response structure validation."""
with patch.object(self.client, "session") as mock_session:
# Create mock response with expected structure
mock_response_data = {
@@ -606,13 +603,16 @@ def test_search_written_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["test_mode"] = True
# Add request body if required
+ # Import and create proper request model instance
+ from xdk.community_notes.models import EvaluateRequest
+ # Create instance with minimal valid data (empty instance should work for most cases)
+ kwargs["body"] = EvaluateRequest()
# Call method and verify response structure
- method = getattr(self.community_notes_client, "search_written")
+ method = getattr(self.community_notes_client, "evaluate")
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_structure.py b/xdk/python/tests/community_notes/test_structure.py
index da78634b..19aae56c 100644
--- a/xdk/python/tests/community_notes/test_structure.py
+++ b/xdk/python/tests/community_notes/test_structure.py
@@ -59,6 +59,7 @@ def test_search_eligible_posts_exists(self):
optional_params = [
"pagination_token",
"max_results",
+ "post_selection",
"tweet.fields",
"expansions",
"media.fields",
@@ -148,31 +149,37 @@ def test_delete_return_annotation(self):
), f"Method delete should have return type annotation"
- def test_evaluate_exists(self):
- """Test that evaluate 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, "evaluate", None)
+ method = getattr(CommunityNotesClient, "search_written", None)
assert (
method is not None
- ), f"Method evaluate does not exist on CommunityNotesClient"
+ ), f"Method search_written does not exist on CommunityNotesClient"
# Check method is callable
- assert callable(method), f"evaluate 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"evaluate 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]}'"
# 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 evaluate"
+ ), f"Required parameter '{required_param}' missing from search_written"
# Check optional parameters have defaults (excluding 'self')
- optional_params = []
+ optional_params = [
+ "pagination_token",
+ "max_results",
+ "note.fields",
+ ]
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -181,14 +188,33 @@ def test_evaluate_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_evaluate_return_annotation(self):
- """Test that evaluate has proper return type annotation."""
- method = getattr(CommunityNotesClient, "evaluate")
+ 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 evaluate should have return type annotation"
+ ), f"Method search_written should have return type annotation"
+
+
+ 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
+ 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_written should have pagination parameters"
def test_create_exists(self):
@@ -234,37 +260,31 @@ def test_create_return_annotation(self):
), f"Method create should have return type annotation"
- def test_search_written_exists(self):
- """Test that search_written method exists with correct signature."""
+ def test_evaluate_exists(self):
+ """Test that evaluate method exists with correct signature."""
# Check method exists
- method = getattr(CommunityNotesClient, "search_written", None)
+ method = getattr(CommunityNotesClient, "evaluate", None)
assert (
method is not None
- ), f"Method search_written does not exist on CommunityNotesClient"
+ ), f"Method evaluate does not exist on CommunityNotesClient"
# Check method is callable
- assert callable(method), f"search_written is not callable"
+ assert callable(method), f"evaluate is not 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_written should have at least 'self' parameter"
+ assert len(params) >= 1, f"evaluate 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",
- ]
+ required_params = []
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from search_written"
+ ), f"Required parameter '{required_param}' missing from evaluate"
# Check optional parameters have defaults (excluding 'self')
- optional_params = [
- "pagination_token",
- "max_results",
- "note.fields",
- ]
+ optional_params = []
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -273,33 +293,14 @@ def test_search_written_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_search_written_return_annotation(self):
- """Test that search_written has proper return type annotation."""
- method = getattr(CommunityNotesClient, "search_written")
+ def test_evaluate_return_annotation(self):
+ """Test that evaluate has proper return type annotation."""
+ method = getattr(CommunityNotesClient, "evaluate")
sig = inspect.signature(method)
# Check return annotation exists
assert (
sig.return_annotation is not inspect.Signature.empty
- ), f"Method search_written should have return type annotation"
-
-
- 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
- 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_written should have pagination parameters"
+ ), f"Method evaluate should have return type annotation"
def test_all_expected_methods_exist(self):
@@ -307,9 +308,9 @@ def test_all_expected_methods_exist(self):
expected_methods = [
"search_eligible_posts",
"delete",
- "evaluate",
- "create",
"search_written",
+ "create",
+ "evaluate",
]
for expected_method in expected_methods:
assert hasattr(
diff --git a/xdk/python/tests/direct_messages/test_contracts.py b/xdk/python/tests/direct_messages/test_contracts.py
index 6266dbd9..b99b113e 100644
--- a/xdk/python/tests/direct_messages/test_contracts.py
+++ b/xdk/python/tests/direct_messages/test_contracts.py
@@ -27,8 +27,8 @@ def setup_class(self):
self.direct_messages_client = getattr(self.client, "direct_messages")
- def test_get_events_by_participant_id_request_structure(self):
- """Test get_events_by_participant_id request structure."""
+ def test_get_events_by_conversation_id_request_structure(self):
+ """Test get_events_by_conversation_id request structure."""
# Mock the session to capture request details
with patch.object(self.client, "session") as mock_session:
mock_response = Mock()
@@ -41,12 +41,12 @@ def test_get_events_by_participant_id_request_structure(self):
# Prepare test parameters
kwargs = {}
# Add required parameters
- kwargs["participant_id"] = "test_value"
+ kwargs["id"] = "test_value"
# Add request body if required
# Call the method
try:
method = getattr(
- self.direct_messages_client, "get_events_by_participant_id"
+ self.direct_messages_client, "get_events_by_conversation_id"
)
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
@@ -82,7 +82,7 @@ def test_get_events_by_participant_id_request_structure(self):
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/{id}/dm_events"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -99,13 +99,13 @@ def test_get_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_events_by_participant_id: {e}"
+ f"Contract test failed for get_events_by_conversation_id: {e}"
)
- def test_get_events_by_participant_id_required_parameters(self):
- """Test that get_events_by_participant_id handles parameters correctly."""
- method = getattr(self.direct_messages_client, "get_events_by_participant_id")
+ def test_get_events_by_conversation_id_required_parameters(self):
+ """Test that get_events_by_conversation_id handles parameters correctly."""
+ method = getattr(self.direct_messages_client, "get_events_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)
@@ -119,8 +119,8 @@ def test_get_events_by_participant_id_required_parameters(self):
method()
- def test_get_events_by_participant_id_response_structure(self):
- """Test get_events_by_participant_id response structure validation."""
+ def test_get_events_by_conversation_id_response_structure(self):
+ """Test get_events_by_conversation_id response structure validation."""
with patch.object(self.client, "session") as mock_session:
# Create mock response with expected structure
mock_response_data = {
@@ -133,11 +133,11 @@ def test_get_events_by_participant_id_response_structure(self):
mock_session.get.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
- kwargs["participant_id"] = "test"
+ kwargs["id"] = "test"
# Add request body if required
# Call method and verify response structure
method = getattr(
- self.direct_messages_client, "get_events_by_participant_id"
+ self.direct_messages_client, "get_events_by_conversation_id"
)
result = method(**kwargs)
# Verify response object has expected attributes
@@ -150,12 +150,12 @@ def test_get_events_by_participant_id_response_structure(self):
)
- def test_create_by_conversation_id_request_structure(self):
- """Test create_by_conversation_id request structure."""
+ def test_create_conversation_request_structure(self):
+ """Test create_conversation 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,
}
@@ -164,17 +164,14 @@ def test_create_by_conversation_id_request_structure(self):
# 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 CreateByConversationIdRequest
+ from xdk.direct_messages.models import CreateConversationRequest
# Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = CreateByConversationIdRequest()
+ kwargs["body"] = CreateConversationRequest()
# Call the method
try:
- method = getattr(
- self.direct_messages_client, "create_by_conversation_id"
- )
+ method = getattr(self.direct_messages_client, "create_conversation")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -183,7 +180,7 @@ def test_create_by_conversation_id_request_structure(self):
# For streaming operations, we need to set up the mock to handle streaming
# Mock the streaming response
mock_streaming_response = Mock()
- mock_streaming_response.status_code = 200
+ mock_streaming_response.status_code = 201
mock_streaming_response.raise_for_status.return_value = None
mock_streaming_response.__enter__ = Mock(
return_value=mock_streaming_response
@@ -209,7 +206,7 @@ def test_create_by_conversation_id_request_structure(self):
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_conversations"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -225,12 +222,12 @@ def test_create_by_conversation_id_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for create_by_conversation_id: {e}")
+ pytest.fail(f"Contract test failed for create_conversation: {e}")
- def test_create_by_conversation_id_required_parameters(self):
- """Test that create_by_conversation_id handles parameters correctly."""
- method = getattr(self.direct_messages_client, "create_by_conversation_id")
+ def test_create_conversation_required_parameters(self):
+ """Test that create_conversation handles parameters correctly."""
+ method = getattr(self.direct_messages_client, "create_conversation")
# 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)
@@ -244,28 +241,27 @@ def test_create_by_conversation_id_required_parameters(self):
method()
- def test_create_by_conversation_id_response_structure(self):
- """Test create_by_conversation_id response structure validation."""
+ def test_create_conversation_response_structure(self):
+ """Test create_conversation 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.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 CreateByConversationIdRequest
+ from xdk.direct_messages.models import CreateConversationRequest
# Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = CreateByConversationIdRequest()
+ kwargs["body"] = CreateConversationRequest()
# Call method and verify response structure
- method = getattr(self.direct_messages_client, "create_by_conversation_id")
+ method = getattr(self.direct_messages_client, "create_conversation")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -277,8 +273,8 @@ def test_create_by_conversation_id_response_structure(self):
)
- def test_get_events_by_conversation_id_request_structure(self):
- """Test get_events_by_conversation_id request structure."""
+ def test_create_by_conversation_id_request_structure(self):
+ """Test create_by_conversation_id request structure."""
# Mock the session to capture request details
with patch.object(self.client, "session") as mock_session:
mock_response = Mock()
@@ -287,16 +283,20 @@ def test_get_events_by_conversation_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
- kwargs["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 CreateByConversationIdRequest
+ # Create instance with minimal valid data (empty instance should work for most cases)
+ kwargs["body"] = CreateByConversationIdRequest()
# Call the method
try:
method = getattr(
- self.direct_messages_client, "get_events_by_conversation_id"
+ self.direct_messages_client, "create_by_conversation_id"
)
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
@@ -316,7 +316,7 @@ def test_get_events_by_conversation_id_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -325,14 +325,14 @@ def test_get_events_by_conversation_id_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/{id}/dm_events"
+ expected_path = "/2/dm_conversations/{dm_conversation_id}/messages"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -348,14 +348,12 @@ def test_get_events_by_conversation_id_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(
- f"Contract test failed for get_events_by_conversation_id: {e}"
- )
+ pytest.fail(f"Contract test failed for create_by_conversation_id: {e}")
- def test_get_events_by_conversation_id_required_parameters(self):
- """Test that get_events_by_conversation_id handles parameters correctly."""
- method = getattr(self.direct_messages_client, "get_events_by_conversation_id")
+ def test_create_by_conversation_id_required_parameters(self):
+ """Test that create_by_conversation_id handles parameters correctly."""
+ method = getattr(self.direct_messages_client, "create_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)
@@ -363,14 +361,14 @@ def test_get_events_by_conversation_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_events_by_conversation_id_response_structure(self):
- """Test get_events_by_conversation_id response structure validation."""
+ def test_create_by_conversation_id_response_structure(self):
+ """Test create_by_conversation_id response structure validation."""
with patch.object(self.client, "session") as mock_session:
# Create mock response with expected structure
mock_response_data = {
@@ -380,15 +378,17 @@ def test_get_events_by_conversation_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"
+ kwargs["dm_conversation_id"] = "test_value"
# Add request body if required
+ # Import and create proper request model instance
+ from xdk.direct_messages.models import CreateByConversationIdRequest
+ # Create instance with minimal valid data (empty instance should work for most cases)
+ kwargs["body"] = CreateByConversationIdRequest()
# Call method and verify response structure
- method = getattr(
- self.direct_messages_client, "get_events_by_conversation_id"
- )
+ method = getattr(self.direct_messages_client, "create_by_conversation_id")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -400,28 +400,27 @@ def test_get_events_by_conversation_id_response_structure(self):
)
- def test_create_conversation_request_structure(self):
- """Test create_conversation request structure."""
+ def test_get_events_by_participant_id_request_structure(self):
+ """Test get_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 CreateConversationRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = CreateConversationRequest()
# Call the method
try:
- method = getattr(self.direct_messages_client, "create_conversation")
+ method = getattr(
+ self.direct_messages_client, "get_events_by_participant_id"
+ )
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -430,7 +429,7 @@ def test_create_conversation_request_structure(self):
# For streaming operations, we need to set up the mock to handle streaming
# Mock the streaming response
mock_streaming_response = Mock()
- mock_streaming_response.status_code = 201
+ mock_streaming_response.status_code = 200
mock_streaming_response.raise_for_status.return_value = None
mock_streaming_response.__enter__ = Mock(
return_value=mock_streaming_response
@@ -440,7 +439,7 @@ def test_create_conversation_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -449,14 +448,14 @@ def test_create_conversation_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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"
+ expected_path = "/2/dm_conversations/with/{participant_id}/dm_events"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -472,12 +471,14 @@ def test_create_conversation_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for create_conversation: {e}")
+ pytest.fail(
+ f"Contract test failed for get_events_by_participant_id: {e}"
+ )
- def test_create_conversation_required_parameters(self):
- """Test that create_conversation handles parameters correctly."""
- method = getattr(self.direct_messages_client, "create_conversation")
+ def test_get_events_by_participant_id_required_parameters(self):
+ """Test that get_events_by_participant_id handles parameters correctly."""
+ method = getattr(self.direct_messages_client, "get_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)
@@ -485,33 +486,32 @@ def test_create_conversation_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_conversation_response_structure(self):
- """Test create_conversation response structure validation."""
+ def test_get_events_by_participant_id_response_structure(self):
+ """Test get_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 CreateConversationRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = CreateConversationRequest()
# Call method and verify response structure
- method = getattr(self.direct_messages_client, "create_conversation")
+ method = getattr(
+ self.direct_messages_client, "get_events_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_pagination.py b/xdk/python/tests/direct_messages/test_pagination.py
index f3567201..30c5f2e6 100644
--- a/xdk/python/tests/direct_messages/test_pagination.py
+++ b/xdk/python/tests/direct_messages/test_pagination.py
@@ -27,9 +27,9 @@ def setup_class(self):
self.direct_messages_client = getattr(self.client, "direct_messages")
- def test_get_events_by_participant_id_cursor_creation(self):
- """Test that get_events_by_participant_id can be used with Cursor."""
- method = getattr(self.direct_messages_client, "get_events_by_participant_id")
+ def test_get_events_by_conversation_id_cursor_creation(self):
+ """Test that get_events_by_conversation_id can be used with Cursor."""
+ method = getattr(self.direct_messages_client, "get_events_by_conversation_id")
# Should be able to create cursor without error
try:
test_cursor = cursor(method, "test_value", max_results=10)
@@ -37,12 +37,12 @@ def test_get_events_by_participant_id_cursor_creation(self):
assert isinstance(test_cursor, Cursor)
except PaginationError:
pytest.fail(
- f"Method get_events_by_participant_id should support pagination"
+ f"Method get_events_by_conversation_id should support pagination"
)
- def test_get_events_by_participant_id_cursor_pages(self):
- """Test pagination with pages() for get_events_by_participant_id."""
+ def test_get_events_by_conversation_id_cursor_pages(self):
+ """Test pagination with pages() for get_events_by_conversation_id."""
with patch.object(self.client, "session") as mock_session:
# Mock first page response
first_page_response = Mock()
@@ -64,7 +64,7 @@ def test_get_events_by_participant_id_cursor_pages(self):
mock_session.get.side_effect = [first_page_response, second_page_response]
# Test pagination
method = getattr(
- self.direct_messages_client, "get_events_by_participant_id"
+ self.direct_messages_client, "get_events_by_conversation_id"
)
test_cursor = cursor(method, "test_value", max_results=2)
pages = list(test_cursor.pages(2)) # Limit to 2 pages
@@ -81,8 +81,8 @@ def test_get_events_by_participant_id_cursor_pages(self):
assert len(second_data) == 1, "Second page should have 1 item"
- def test_get_events_by_participant_id_cursor_items(self):
- """Test pagination with items() for get_events_by_participant_id."""
+ def test_get_events_by_conversation_id_cursor_items(self):
+ """Test pagination with items() for get_events_by_conversation_id."""
with patch.object(self.client, "session") as mock_session:
# Mock response with paginated data
mock_response = Mock()
@@ -102,7 +102,7 @@ def test_get_events_by_participant_id_cursor_items(self):
mock_session.get.return_value = mock_response
# Test item iteration
method = getattr(
- self.direct_messages_client, "get_events_by_participant_id"
+ self.direct_messages_client, "get_events_by_conversation_id"
)
test_cursor = cursor(method, "test_value", max_results=10)
items = list(test_cursor.items(5)) # Limit to 5 items
@@ -114,8 +114,8 @@ def test_get_events_by_participant_id_cursor_items(self):
), "Items should have 'id' field"
- def test_get_events_by_participant_id_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_events_by_participant_id."""
+ def test_get_events_by_conversation_id_pagination_parameters(self):
+ """Test that pagination parameters are handled correctly for get_events_by_conversation_id."""
with patch.object(self.client, "session") as mock_session:
mock_response = Mock()
mock_response.status_code = 200
@@ -123,7 +123,7 @@ def test_get_events_by_participant_id_pagination_parameters(self):
mock_response.raise_for_status.return_value = None
mock_session.get.return_value = mock_response
method = getattr(
- self.direct_messages_client, "get_events_by_participant_id"
+ self.direct_messages_client, "get_events_by_conversation_id"
)
# Test with max_results parameter
test_cursor = cursor(method, "test_value", max_results=5)
@@ -177,9 +177,9 @@ def test_get_events_by_participant_id_pagination_parameters(self):
), "Pagination token should be passed correctly"
- def test_get_events_by_conversation_id_cursor_creation(self):
- """Test that get_events_by_conversation_id can be used with Cursor."""
- method = getattr(self.direct_messages_client, "get_events_by_conversation_id")
+ def test_get_events_by_participant_id_cursor_creation(self):
+ """Test that get_events_by_participant_id can be used with Cursor."""
+ method = getattr(self.direct_messages_client, "get_events_by_participant_id")
# Should be able to create cursor without error
try:
test_cursor = cursor(method, "test_value", max_results=10)
@@ -187,12 +187,12 @@ def test_get_events_by_conversation_id_cursor_creation(self):
assert isinstance(test_cursor, Cursor)
except PaginationError:
pytest.fail(
- f"Method get_events_by_conversation_id should support pagination"
+ f"Method get_events_by_participant_id should support pagination"
)
- def test_get_events_by_conversation_id_cursor_pages(self):
- """Test pagination with pages() for get_events_by_conversation_id."""
+ def test_get_events_by_participant_id_cursor_pages(self):
+ """Test pagination with pages() for get_events_by_participant_id."""
with patch.object(self.client, "session") as mock_session:
# Mock first page response
first_page_response = Mock()
@@ -214,7 +214,7 @@ def test_get_events_by_conversation_id_cursor_pages(self):
mock_session.get.side_effect = [first_page_response, second_page_response]
# Test pagination
method = getattr(
- self.direct_messages_client, "get_events_by_conversation_id"
+ self.direct_messages_client, "get_events_by_participant_id"
)
test_cursor = cursor(method, "test_value", max_results=2)
pages = list(test_cursor.pages(2)) # Limit to 2 pages
@@ -231,8 +231,8 @@ def test_get_events_by_conversation_id_cursor_pages(self):
assert len(second_data) == 1, "Second page should have 1 item"
- def test_get_events_by_conversation_id_cursor_items(self):
- """Test pagination with items() for get_events_by_conversation_id."""
+ def test_get_events_by_participant_id_cursor_items(self):
+ """Test pagination with items() for get_events_by_participant_id."""
with patch.object(self.client, "session") as mock_session:
# Mock response with paginated data
mock_response = Mock()
@@ -252,7 +252,7 @@ def test_get_events_by_conversation_id_cursor_items(self):
mock_session.get.return_value = mock_response
# Test item iteration
method = getattr(
- self.direct_messages_client, "get_events_by_conversation_id"
+ self.direct_messages_client, "get_events_by_participant_id"
)
test_cursor = cursor(method, "test_value", max_results=10)
items = list(test_cursor.items(5)) # Limit to 5 items
@@ -264,8 +264,8 @@ def test_get_events_by_conversation_id_cursor_items(self):
), "Items should have 'id' field"
- def test_get_events_by_conversation_id_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_events_by_conversation_id."""
+ def test_get_events_by_participant_id_pagination_parameters(self):
+ """Test that pagination parameters are handled correctly for get_events_by_participant_id."""
with patch.object(self.client, "session") as mock_session:
mock_response = Mock()
mock_response.status_code = 200
@@ -273,7 +273,7 @@ def test_get_events_by_conversation_id_pagination_parameters(self):
mock_response.raise_for_status.return_value = None
mock_session.get.return_value = mock_response
method = getattr(
- self.direct_messages_client, "get_events_by_conversation_id"
+ self.direct_messages_client, "get_events_by_participant_id"
)
# Test with max_results parameter
test_cursor = cursor(method, "test_value", max_results=5)
@@ -480,7 +480,7 @@ def test_pagination_edge_cases(self):
mock_session.get.return_value = empty_response
# Pick first paginatable method for testing
method = getattr(
- self.direct_messages_client, "get_events_by_participant_id"
+ self.direct_messages_client, "get_events_by_conversation_id"
)
test_cursor = cursor(method, "test_value", max_results=10)
# Should handle empty responses gracefully
diff --git a/xdk/python/tests/direct_messages/test_structure.py b/xdk/python/tests/direct_messages/test_structure.py
index 92c3ccb9..2122862f 100644
--- a/xdk/python/tests/direct_messages/test_structure.py
+++ b/xdk/python/tests/direct_messages/test_structure.py
@@ -28,33 +28,33 @@ def setup_class(self):
self.direct_messages_client = getattr(self.client, "direct_messages")
- def test_get_events_by_participant_id_exists(self):
- """Test that get_events_by_participant_id method exists with correct signature."""
+ def test_get_events_by_conversation_id_exists(self):
+ """Test that get_events_by_conversation_id method exists with correct signature."""
# Check method exists
- method = getattr(DirectMessagesClient, "get_events_by_participant_id", None)
+ method = getattr(DirectMessagesClient, "get_events_by_conversation_id", None)
assert (
method is not None
- ), f"Method get_events_by_participant_id does not exist on DirectMessagesClient"
+ ), f"Method get_events_by_conversation_id does not exist on DirectMessagesClient"
# Check method is callable
- assert callable(method), f"get_events_by_participant_id is not callable"
+ assert callable(method), f"get_events_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_events_by_participant_id should have at least 'self' parameter"
+ ), f"get_events_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",
+ "id",
]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_events_by_participant_id"
+ ), f"Required parameter '{required_param}' missing from get_events_by_conversation_id"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
"max_results",
@@ -74,19 +74,19 @@ def test_get_events_by_participant_id_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_events_by_participant_id_return_annotation(self):
- """Test that get_events_by_participant_id has proper return type annotation."""
- method = getattr(DirectMessagesClient, "get_events_by_participant_id")
+ def test_get_events_by_conversation_id_return_annotation(self):
+ """Test that get_events_by_conversation_id has proper return type annotation."""
+ method = getattr(DirectMessagesClient, "get_events_by_conversation_id")
sig = inspect.signature(method)
# Check return annotation exists
assert (
sig.return_annotation is not inspect.Signature.empty
- ), f"Method get_events_by_participant_id should have return type annotation"
+ ), f"Method get_events_by_conversation_id should have return type annotation"
- def test_get_events_by_participant_id_pagination_params(self):
- """Test that get_events_by_participant_id has pagination parameters."""
- method = getattr(DirectMessagesClient, "get_events_by_participant_id")
+ def test_get_events_by_conversation_id_pagination_params(self):
+ """Test that get_events_by_conversation_id has pagination parameters."""
+ method = getattr(DirectMessagesClient, "get_events_by_conversation_id")
sig = inspect.signature(method)
params = list(sig.parameters.keys())
# Should have pagination-related parameters
@@ -100,7 +100,52 @@ def test_get_events_by_participant_id_pagination_params(self):
has_pagination_param = any(param in params for param in pagination_params)
assert (
has_pagination_param
- ), f"Paginated method get_events_by_participant_id should have pagination parameters"
+ ), f"Paginated method get_events_by_conversation_id should have pagination parameters"
+
+
+ def test_create_conversation_exists(self):
+ """Test that create_conversation method exists with correct signature."""
+ # Check method exists
+ method = getattr(DirectMessagesClient, "create_conversation", None)
+ assert (
+ method is not None
+ ), f"Method create_conversation does not exist on DirectMessagesClient"
+ # Check method is callable
+ assert callable(method), f"create_conversation is not 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_conversation 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_conversation"
+ # 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_conversation_return_annotation(self):
+ """Test that create_conversation has proper return type annotation."""
+ method = getattr(DirectMessagesClient, "create_conversation")
+ sig = inspect.signature(method)
+ # Check return annotation exists
+ assert (
+ sig.return_annotation is not inspect.Signature.empty
+ ), f"Method create_conversation should have return type annotation"
def test_create_by_conversation_id_exists(self):
@@ -150,33 +195,33 @@ def test_create_by_conversation_id_return_annotation(self):
), f"Method create_by_conversation_id should have return type annotation"
- def test_get_events_by_conversation_id_exists(self):
- """Test that get_events_by_conversation_id method exists with correct signature."""
+ def test_get_events_by_participant_id_exists(self):
+ """Test that get_events_by_participant_id method exists with correct signature."""
# Check method exists
- method = getattr(DirectMessagesClient, "get_events_by_conversation_id", None)
+ method = getattr(DirectMessagesClient, "get_events_by_participant_id", None)
assert (
method is not None
- ), f"Method get_events_by_conversation_id does not exist on DirectMessagesClient"
+ ), f"Method get_events_by_participant_id does not exist on DirectMessagesClient"
# Check method is callable
- assert callable(method), f"get_events_by_conversation_id is not callable"
+ assert callable(method), f"get_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_events_by_conversation_id should have at least 'self' parameter"
+ ), f"get_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 = [
- "id",
+ "participant_id",
]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_events_by_conversation_id"
+ ), f"Required parameter '{required_param}' missing from get_events_by_participant_id"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
"max_results",
@@ -196,19 +241,19 @@ def test_get_events_by_conversation_id_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_events_by_conversation_id_return_annotation(self):
- """Test that get_events_by_conversation_id has proper return type annotation."""
- method = getattr(DirectMessagesClient, "get_events_by_conversation_id")
+ def test_get_events_by_participant_id_return_annotation(self):
+ """Test that get_events_by_participant_id has proper return type annotation."""
+ method = getattr(DirectMessagesClient, "get_events_by_participant_id")
sig = inspect.signature(method)
# Check return annotation exists
assert (
sig.return_annotation is not inspect.Signature.empty
- ), f"Method get_events_by_conversation_id should have return type annotation"
+ ), f"Method get_events_by_participant_id should have return type annotation"
- def test_get_events_by_conversation_id_pagination_params(self):
- """Test that get_events_by_conversation_id has pagination parameters."""
- method = getattr(DirectMessagesClient, "get_events_by_conversation_id")
+ def test_get_events_by_participant_id_pagination_params(self):
+ """Test that get_events_by_participant_id has pagination parameters."""
+ method = getattr(DirectMessagesClient, "get_events_by_participant_id")
sig = inspect.signature(method)
params = list(sig.parameters.keys())
# Should have pagination-related parameters
@@ -222,52 +267,7 @@ def test_get_events_by_conversation_id_pagination_params(self):
has_pagination_param = any(param in params for param in pagination_params)
assert (
has_pagination_param
- ), f"Paginated method get_events_by_conversation_id should have pagination parameters"
-
-
- def test_create_conversation_exists(self):
- """Test that create_conversation method exists with correct signature."""
- # Check method exists
- method = getattr(DirectMessagesClient, "create_conversation", None)
- assert (
- method is not None
- ), f"Method create_conversation does not exist on DirectMessagesClient"
- # Check method is callable
- assert callable(method), f"create_conversation is not 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_conversation 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_conversation"
- # 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_conversation_return_annotation(self):
- """Test that create_conversation has proper return type annotation."""
- method = getattr(DirectMessagesClient, "create_conversation")
- sig = inspect.signature(method)
- # Check return annotation exists
- assert (
- sig.return_annotation is not inspect.Signature.empty
- ), f"Method create_conversation should have return type annotation"
+ ), f"Paginated method get_events_by_participant_id should have pagination parameters"
def test_get_events_exists(self):
@@ -489,10 +489,10 @@ def test_delete_events_return_annotation(self):
def test_all_expected_methods_exist(self):
"""Test that all expected methods exist on the client."""
expected_methods = [
- "get_events_by_participant_id",
- "create_by_conversation_id",
"get_events_by_conversation_id",
"create_conversation",
+ "create_by_conversation_id",
+ "get_events_by_participant_id",
"get_events",
"create_by_participant_id",
"get_events_by_id",
diff --git a/xdk/python/tests/lists/test_contracts.py b/xdk/python/tests/lists/test_contracts.py
index 6bdacf2f..8a091c17 100644
--- a/xdk/python/tests/lists/test_contracts.py
+++ b/xdk/python/tests/lists/test_contracts.py
@@ -27,8 +27,8 @@ def setup_class(self):
self.lists_client = getattr(self.client, "lists")
- def test_get_followers_request_structure(self):
- """Test get_followers 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()
@@ -37,15 +37,18 @@ def test_get_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.lists.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.lists_client, "get_followers")
+ method = getattr(self.lists_client, "create")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -64,7 +67,7 @@ def test_get_followers_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -73,14 +76,14 @@ def test_get_followers_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/lists"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -96,12 +99,12 @@ def test_get_followers_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_followers: {e}")
+ pytest.fail(f"Contract test failed for create: {e}")
- def test_get_followers_required_parameters(self):
- """Test that get_followers handles parameters correctly."""
- method = getattr(self.lists_client, "get_followers")
+ 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)
@@ -109,14 +112,14 @@ def test_get_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_followers_response_structure(self):
- """Test get_followers 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 = {
@@ -126,13 +129,16 @@ def test_get_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.lists.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.lists_client, "get_followers")
+ 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
@@ -144,8 +150,8 @@ def test_get_followers_response_structure(self):
)
- def test_get_members_request_structure(self):
- """Test get_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()
@@ -162,7 +168,7 @@ def test_get_members_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.lists_client, "get_members")
+ method = getattr(self.lists_client, "get_by_id")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -197,7 +203,7 @@ def test_get_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/lists/{id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -213,12 +219,12 @@ def test_get_members_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_members: {e}")
+ pytest.fail(f"Contract test failed for get_by_id: {e}")
- def test_get_members_required_parameters(self):
- """Test that get_members handles parameters correctly."""
- method = getattr(self.lists_client, "get_members")
+ 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)
@@ -232,8 +238,8 @@ def test_get_members_required_parameters(self):
method()
- def test_get_members_response_structure(self):
- """Test get_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 = {
@@ -249,7 +255,7 @@ def test_get_members_response_structure(self):
kwargs["id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.lists_client, "get_members")
+ 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
@@ -261,8 +267,8 @@ def test_get_members_response_structure(self):
)
- def test_add_member_request_structure(self):
- """Test add_member 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()
@@ -271,19 +277,19 @@ def test_add_member_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 AddMemberRequest
+ from xdk.lists.models import UpdateRequest
# Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = AddMemberRequest()
+ kwargs["body"] = UpdateRequest()
# Call the method
try:
- method = getattr(self.lists_client, "add_member")
+ method = getattr(self.lists_client, "update")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -302,7 +308,7 @@ def test_add_member_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.put.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -311,14 +317,14 @@ def test_add_member_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/lists/{id}/members"
+ expected_path = "/2/lists/{id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -334,12 +340,12 @@ def test_add_member_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for add_member: {e}")
+ pytest.fail(f"Contract test failed for update: {e}")
- def test_add_member_required_parameters(self):
- """Test that add_member handles parameters correctly."""
- method = getattr(self.lists_client, "add_member")
+ 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)
@@ -347,14 +353,14 @@ def test_add_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.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_add_member_response_structure(self):
- """Test add_member 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 = {
@@ -364,17 +370,17 @@ def test_add_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.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 AddMemberRequest
+ from xdk.lists.models import UpdateRequest
# Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = AddMemberRequest()
+ kwargs["body"] = UpdateRequest()
# Call method and verify response structure
- method = getattr(self.lists_client, "add_member")
+ 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
@@ -386,8 +392,8 @@ def test_add_member_response_structure(self):
)
- def test_get_posts_request_structure(self):
- """Test get_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()
@@ -396,7 +402,7 @@ def test_get_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
@@ -404,7 +410,7 @@ def test_get_posts_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.lists_client, "get_posts")
+ method = getattr(self.lists_client, "delete")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -423,7 +429,7 @@ def test_get_posts_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.delete.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -432,14 +438,14 @@ def test_get_posts_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/lists/{id}/tweets"
+ expected_path = "/2/lists/{id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -455,12 +461,12 @@ def test_get_posts_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_posts: {e}")
+ pytest.fail(f"Contract test failed for delete: {e}")
- def test_get_posts_required_parameters(self):
- """Test that get_posts handles parameters correctly."""
- method = getattr(self.lists_client, "get_posts")
+ 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)
@@ -468,14 +474,14 @@ def test_get_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_get_posts_response_structure(self):
- """Test get_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 = {
@@ -485,13 +491,13 @@ def test_get_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["id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.lists_client, "get_posts")
+ 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
@@ -503,8 +509,8 @@ def test_get_posts_response_structure(self):
)
- def test_create_request_structure(self):
- """Test create 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()
@@ -513,18 +519,15 @@ def test_create_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 CreateRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = CreateRequest()
# Call the method
try:
- method = getattr(self.lists_client, "create")
+ method = getattr(self.lists_client, "get_followers")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -543,7 +546,7 @@ def test_create_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -552,14 +555,14 @@ def test_create_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/lists"
+ expected_path = "/2/lists/{id}/followers"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -575,12 +578,12 @@ def test_create_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for create: {e}")
+ pytest.fail(f"Contract test failed for get_followers: {e}")
- def test_create_required_parameters(self):
- """Test that create handles parameters correctly."""
- method = getattr(self.lists_client, "create")
+ 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)
@@ -588,14 +591,14 @@ def test_create_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_response_structure(self):
- """Test create 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 = {
@@ -605,16 +608,13 @@ def test_create_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 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.lists_client, "create")
+ 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
@@ -745,8 +745,8 @@ def test_remove_member_by_user_id_response_structure(self):
)
- def test_get_by_id_request_structure(self):
- """Test get_by_id 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()
@@ -763,7 +763,7 @@ def test_get_by_id_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.lists_client, "get_by_id")
+ method = getattr(self.lists_client, "get_posts")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -798,7 +798,7 @@ def test_get_by_id_request_structure(self):
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}/tweets"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -814,12 +814,12 @@ def test_get_by_id_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_by_id: {e}")
+ pytest.fail(f"Contract test failed for get_posts: {e}")
- def test_get_by_id_required_parameters(self):
- """Test that get_by_id handles parameters correctly."""
- method = getattr(self.lists_client, "get_by_id")
+ 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)
@@ -833,8 +833,8 @@ def test_get_by_id_required_parameters(self):
method()
- def test_get_by_id_response_structure(self):
- """Test get_by_id 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 = {
@@ -850,7 +850,7 @@ def test_get_by_id_response_structure(self):
kwargs["id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.lists_client, "get_by_id")
+ 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
@@ -862,8 +862,8 @@ def test_get_by_id_response_structure(self):
)
- def test_update_request_structure(self):
- """Test update 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()
@@ -872,19 +872,15 @@ def test_update_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 UpdateRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = UpdateRequest()
# Call the method
try:
- method = getattr(self.lists_client, "update")
+ method = getattr(self.lists_client, "get_members")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -903,7 +899,7 @@ def test_update_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.put.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -912,14 +908,14 @@ def test_update_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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(
@@ -935,12 +931,12 @@ def test_update_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for update: {e}")
+ pytest.fail(f"Contract test failed for get_members: {e}")
- def test_update_required_parameters(self):
- """Test that update handles parameters correctly."""
- method = getattr(self.lists_client, "update")
+ 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)
@@ -948,14 +944,14 @@ def test_update_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_response_structure(self):
- """Test update 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 = {
@@ -965,17 +961,13 @@ def test_update_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 UpdateRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = UpdateRequest()
# Call method and verify response structure
- method = getattr(self.lists_client, "update")
+ 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
@@ -987,8 +979,8 @@ def test_update_response_structure(self):
)
- def test_delete_request_structure(self):
- """Test delete 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()
@@ -997,15 +989,19 @@ def test_delete_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")
+ method = getattr(self.lists_client, "add_member")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1024,7 +1020,7 @@ def test_delete_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.delete.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -1033,14 +1029,14 @@ def test_delete_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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(
@@ -1056,12 +1052,12 @@ def test_delete_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for delete: {e}")
+ pytest.fail(f"Contract test failed for add_member: {e}")
- def test_delete_required_parameters(self):
- """Test that delete handles parameters correctly."""
- method = getattr(self.lists_client, "delete")
+ 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)
@@ -1069,14 +1065,14 @@ def test_delete_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_response_structure(self):
- """Test delete 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 = {
@@ -1086,13 +1082,17 @@ def test_delete_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")
+ 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
diff --git a/xdk/python/tests/lists/test_pagination.py b/xdk/python/tests/lists/test_pagination.py
index a6c7d70b..917c561b 100644
--- a/xdk/python/tests/lists/test_pagination.py
+++ b/xdk/python/tests/lists/test_pagination.py
@@ -169,20 +169,20 @@ def test_get_followers_pagination_parameters(self):
), "Pagination token should be passed correctly"
- def test_get_members_cursor_creation(self):
- """Test that get_members can be used with Cursor."""
- method = getattr(self.lists_client, "get_members")
+ 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_value", max_results=10)
assert test_cursor is not None
assert isinstance(test_cursor, Cursor)
except PaginationError:
- pytest.fail(f"Method get_members should support pagination")
+ pytest.fail(f"Method get_posts should support pagination")
- def test_get_members_cursor_pages(self):
- """Test pagination with pages() for get_members."""
+ 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()
@@ -203,7 +203,7 @@ def test_get_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.lists_client, "get_members")
+ method = getattr(self.lists_client, "get_posts")
test_cursor = cursor(method, "test_value", 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)}"
@@ -219,8 +219,8 @@ def test_get_members_cursor_pages(self):
assert len(second_data) == 1, "Second page should have 1 item"
- def test_get_members_cursor_items(self):
- """Test pagination with items() for get_members."""
+ 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()
@@ -239,7 +239,7 @@ def test_get_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.lists_client, "get_members")
+ method = getattr(self.lists_client, "get_posts")
test_cursor = cursor(method, "test_value", 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)}"
@@ -250,15 +250,15 @@ def test_get_members_cursor_items(self):
), "Items should have 'id' field"
- def test_get_members_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_members."""
+ 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_members")
+ method = getattr(self.lists_client, "get_posts")
# Test with max_results parameter
test_cursor = cursor(method, "test_value", max_results=5)
list(test_cursor.pages(1)) # Trigger one request
@@ -311,20 +311,20 @@ def test_get_members_pagination_parameters(self):
), "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.lists_client, "get_posts")
+ 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_value", 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")
+ pytest.fail(f"Method get_members should support pagination")
- def test_get_posts_cursor_pages(self):
- """Test pagination with pages() for get_posts."""
+ 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()
@@ -345,7 +345,7 @@ def test_get_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.lists_client, "get_posts")
+ method = getattr(self.lists_client, "get_members")
test_cursor = cursor(method, "test_value", 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)}"
@@ -361,8 +361,8 @@ def test_get_posts_cursor_pages(self):
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."""
+ 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()
@@ -381,7 +381,7 @@ def test_get_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.lists_client, "get_posts")
+ method = getattr(self.lists_client, "get_members")
test_cursor = cursor(method, "test_value", 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)}"
@@ -392,15 +392,15 @@ def test_get_posts_cursor_items(self):
), "Items should have 'id' field"
- def test_get_posts_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_posts."""
+ 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_posts")
+ method = getattr(self.lists_client, "get_members")
# Test with max_results parameter
test_cursor = cursor(method, "test_value", max_results=5)
list(test_cursor.pages(1)) # Trigger one request
diff --git a/xdk/python/tests/lists/test_structure.py b/xdk/python/tests/lists/test_structure.py
index fb0f0f39..8a60a975 100644
--- a/xdk/python/tests/lists/test_structure.py
+++ b/xdk/python/tests/lists/test_structure.py
@@ -28,37 +28,29 @@ def setup_class(self):
self.lists_client = getattr(self.client, "lists")
- def test_get_followers_exists(self):
- """Test that get_followers method exists with correct signature."""
+ def test_create_exists(self):
+ """Test that create method exists with correct signature."""
# Check method exists
- method = getattr(ListsClient, "get_followers", None)
- assert method is not None, f"Method get_followers 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"get_followers 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_followers 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 get_followers"
+ ), f"Required parameter '{required_param}' missing from create"
# Check optional parameters have defaults (excluding 'self')
- optional_params = [
- "max_results",
- "pagination_token",
- "user.fields",
- "expansions",
- "tweet.fields",
- ]
+ optional_params = []
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -67,47 +59,28 @@ def test_get_followers_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_followers_return_annotation(self):
- """Test that get_followers has proper return type annotation."""
- method = getattr(ListsClient, "get_followers")
+ 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 get_followers should have return type annotation"
-
-
- 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"
+ ), f"Method create should have return type annotation"
- def test_get_members_exists(self):
- """Test that get_members 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_members", None)
- assert method is not None, f"Method get_members 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_members 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_members 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]}'"
@@ -118,14 +91,12 @@ def test_get_members_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_members"
+ ), f"Required parameter '{required_param}' missing from get_by_id"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "max_results",
- "pagination_token",
- "user.fields",
+ "list.fields",
"expansions",
- "tweet.fields",
+ "user.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -135,47 +106,28 @@ def test_get_members_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_members_return_annotation(self):
- """Test that get_members has proper return type annotation."""
- method = getattr(ListsClient, "get_members")
+ 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_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"
+ ), f"Method get_by_id should have return type annotation"
- def test_add_member_exists(self):
- """Test that add_member method exists with correct signature."""
+ def test_update_exists(self):
+ """Test that update method exists with correct signature."""
# Check method exists
- method = getattr(ListsClient, "add_member", None)
- assert method is not None, f"Method add_member 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"add_member 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"add_member 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]}'"
@@ -186,7 +138,7 @@ def test_add_member_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from add_member"
+ ), f"Required parameter '{required_param}' missing from update"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -197,28 +149,28 @@ def test_add_member_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_add_member_return_annotation(self):
- """Test that add_member has proper return type annotation."""
- method = getattr(ListsClient, "add_member")
+ 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 add_member should have return type annotation"
+ ), f"Method update should have return type annotation"
- def test_get_posts_exists(self):
- """Test that get_posts 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_posts", None)
- assert method is not None, f"Method get_posts 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_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"get_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]}'"
@@ -229,18 +181,9 @@ def test_get_posts_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_posts"
+ ), f"Required parameter '{required_param}' missing from delete"
# Check optional parameters have defaults (excluding 'self')
- optional_params = [
- "max_results",
- "pagination_token",
- "tweet.fields",
- "expansions",
- "media.fields",
- "poll.fields",
- "user.fields",
- "place.fields",
- ]
+ optional_params = []
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -249,58 +192,47 @@ def test_get_posts_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_posts_return_annotation(self):
- """Test that get_posts has proper return type annotation."""
- method = getattr(ListsClient, "get_posts")
+ 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_posts should have return type annotation"
-
-
- 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"
+ ), f"Method delete should have return type annotation"
- def test_create_exists(self):
- """Test that create 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, "create", None)
- assert method is not None, f"Method create 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"create 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"create 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]}'"
# 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 create"
+ ), f"Required parameter '{required_param}' missing from get_followers"
# Check optional parameters have defaults (excluding 'self')
- optional_params = []
+ optional_params = [
+ "max_results",
+ "pagination_token",
+ "user.fields",
+ "expansions",
+ "tweet.fields",
+ ]
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -309,14 +241,33 @@ def test_create_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_create_return_annotation(self):
- """Test that create has proper return type annotation."""
- method = getattr(ListsClient, "create")
+ 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 create should have return type annotation"
+ ), f"Method get_followers should have return type annotation"
+
+
+ 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_remove_member_by_user_id_exists(self):
@@ -367,18 +318,18 @@ def test_remove_member_by_user_id_return_annotation(self):
), f"Method remove_member_by_user_id should have return type annotation"
- def test_get_by_id_exists(self):
- """Test that get_by_id 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(ListsClient, "get_by_id", None)
- assert method is not None, f"Method get_by_id 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"get_by_id 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_by_id 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]}'"
@@ -389,12 +340,17 @@ def test_get_by_id_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_by_id"
+ ), f"Required parameter '{required_param}' missing from get_posts"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "list.fields",
+ "max_results",
+ "pagination_token",
+ "tweet.fields",
"expansions",
+ "media.fields",
+ "poll.fields",
"user.fields",
+ "place.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -404,28 +360,47 @@ def test_get_by_id_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_by_id_return_annotation(self):
- """Test that get_by_id has proper return type annotation."""
- method = getattr(ListsClient, "get_by_id")
+ 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 get_by_id should have return type annotation"
+ ), f"Method get_posts should have return type annotation"
- def test_update_exists(self):
- """Test that update 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_get_members_exists(self):
+ """Test that get_members method exists with correct signature."""
# Check method exists
- method = getattr(ListsClient, "update", None)
- assert method is not None, f"Method update 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 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 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]}'"
@@ -436,9 +411,15 @@ def test_update_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from update"
+ ), f"Required parameter '{required_param}' missing from get_members"
# Check optional parameters have defaults (excluding 'self')
- optional_params = []
+ optional_params = [
+ "max_results",
+ "pagination_token",
+ "user.fields",
+ "expansions",
+ "tweet.fields",
+ ]
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -447,28 +428,47 @@ def test_update_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_update_return_annotation(self):
- """Test that update has proper return type annotation."""
- method = getattr(ListsClient, "update")
+ 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 should have return type annotation"
+ ), f"Method get_members should have return type annotation"
- def test_delete_exists(self):
- """Test that delete method exists with correct signature."""
+ 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_add_member_exists(self):
+ """Test that add_member method exists with correct signature."""
# Check method exists
- method = getattr(ListsClient, "delete", None)
- assert method is not None, f"Method delete 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 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 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]}'"
@@ -479,7 +479,7 @@ def test_delete_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from delete"
+ ), f"Required parameter '{required_param}' missing from add_member"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -490,28 +490,28 @@ def test_delete_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_delete_return_annotation(self):
- """Test that delete has proper return type annotation."""
- method = getattr(ListsClient, "delete")
+ 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 should have return type annotation"
+ ), f"Method add_member should have return type annotation"
def test_all_expected_methods_exist(self):
"""Test that all expected methods exist on the client."""
expected_methods = [
- "get_followers",
- "get_members",
- "add_member",
- "get_posts",
"create",
- "remove_member_by_user_id",
"get_by_id",
"update",
"delete",
+ "get_followers",
+ "remove_member_by_user_id",
+ "get_posts",
+ "get_members",
+ "add_member",
]
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 a1b5a2fd..46021ded 100644
--- a/xdk/python/tests/media/test_contracts.py
+++ b/xdk/python/tests/media/test_contracts.py
@@ -27,8 +27,8 @@ def setup_class(self):
self.media_client = getattr(self.client, "media")
- def test_create_subtitles_request_structure(self):
- """Test create_subtitles 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()
@@ -37,18 +37,15 @@ def test_create_subtitles_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 CreateSubtitlesRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = CreateSubtitlesRequest()
# Call the method
try:
- method = getattr(self.media_client, "create_subtitles")
+ method = getattr(self.media_client, "get_upload_status")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -67,7 +64,7 @@ def test_create_subtitles_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -76,14 +73,14 @@ def test_create_subtitles_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/subtitles"
+ expected_path = "/2/media/upload"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -99,12 +96,12 @@ def test_create_subtitles_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for create_subtitles: {e}")
+ pytest.fail(f"Contract test failed for get_upload_status: {e}")
- def test_create_subtitles_required_parameters(self):
- """Test that create_subtitles handles parameters correctly."""
- method = getattr(self.media_client, "create_subtitles")
+ 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)
@@ -112,14 +109,14 @@ def test_create_subtitles_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_subtitles_response_structure(self):
- """Test create_subtitles 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 = {
@@ -129,16 +126,13 @@ def test_create_subtitles_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 CreateSubtitlesRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = CreateSubtitlesRequest()
# Call method and verify response structure
- method = getattr(self.media_client, "create_subtitles")
+ 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
@@ -150,8 +144,8 @@ def test_create_subtitles_response_structure(self):
)
- def test_delete_subtitles_request_structure(self):
- """Test delete_subtitles 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()
@@ -160,18 +154,18 @@ def test_delete_subtitles_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
# Add request body if required
# Import and create proper request model instance
- from xdk.media.models import DeleteSubtitlesRequest
+ from xdk.media.models import UploadRequest
# Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = DeleteSubtitlesRequest()
+ kwargs["body"] = UploadRequest()
# Call the method
try:
- method = getattr(self.media_client, "delete_subtitles")
+ method = getattr(self.media_client, "upload")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -190,7 +184,7 @@ def test_delete_subtitles_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.delete.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -199,14 +193,14 @@ def test_delete_subtitles_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/media/subtitles"
+ expected_path = "/2/media/upload"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -222,12 +216,12 @@ def test_delete_subtitles_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for delete_subtitles: {e}")
+ pytest.fail(f"Contract test failed for upload: {e}")
- def test_delete_subtitles_required_parameters(self):
- """Test that delete_subtitles handles parameters correctly."""
- method = getattr(self.media_client, "delete_subtitles")
+ 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)
@@ -235,14 +229,14 @@ def test_delete_subtitles_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_subtitles_response_structure(self):
- """Test delete_subtitles 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 = {
@@ -252,16 +246,16 @@ def test_delete_subtitles_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 = {}
# Add request body if required
# Import and create proper request model instance
- from xdk.media.models import DeleteSubtitlesRequest
+ from xdk.media.models import UploadRequest
# Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = DeleteSubtitlesRequest()
+ kwargs["body"] = UploadRequest()
# Call method and verify response structure
- method = getattr(self.media_client, "delete_subtitles")
+ 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
@@ -273,8 +267,8 @@ def test_delete_subtitles_response_structure(self):
)
- def test_get_analytics_request_structure(self):
- """Test get_analytics 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()
@@ -283,18 +277,18 @@ def test_get_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"
# Add request body if required
+ # Import and create proper request model instance
+ from xdk.media.models import CreateSubtitlesRequest
+ # Create instance with minimal valid data (empty instance should work for most cases)
+ kwargs["body"] = CreateSubtitlesRequest()
# Call the method
try:
- method = getattr(self.media_client, "get_analytics")
+ method = getattr(self.media_client, "create_subtitles")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -313,7 +307,7 @@ def test_get_analytics_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -322,14 +316,14 @@ def test_get_analytics_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/subtitles"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -345,12 +339,12 @@ def test_get_analytics_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_analytics: {e}")
+ pytest.fail(f"Contract test failed for create_subtitles: {e}")
- def test_get_analytics_required_parameters(self):
- """Test that get_analytics handles parameters correctly."""
- method = getattr(self.media_client, "get_analytics")
+ 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)
@@ -358,14 +352,14 @@ def test_get_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_analytics_response_structure(self):
- """Test get_analytics 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 = {
@@ -375,16 +369,16 @@ def test_get_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"
# Add request body if required
+ # Import and create proper request model instance
+ from xdk.media.models import CreateSubtitlesRequest
+ # Create instance with minimal valid data (empty instance should work for most cases)
+ kwargs["body"] = CreateSubtitlesRequest()
# Call method and verify response structure
- method = getattr(self.media_client, "get_analytics")
+ 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
@@ -396,8 +390,8 @@ def test_get_analytics_response_structure(self):
)
- def test_get_by_keys_request_structure(self):
- """Test get_by_keys 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()
@@ -406,15 +400,18 @@ def test_get_by_keys_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["media_keys"] = ["test_item"]
# Add request body if required
+ # Import and create proper request model instance
+ from xdk.media.models import DeleteSubtitlesRequest
+ # Create instance with minimal valid data (empty instance should work for most cases)
+ kwargs["body"] = DeleteSubtitlesRequest()
# Call the method
try:
- method = getattr(self.media_client, "get_by_keys")
+ method = getattr(self.media_client, "delete_subtitles")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -433,7 +430,7 @@ def test_get_by_keys_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.delete.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -442,14 +439,14 @@ def test_get_by_keys_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/media"
+ expected_path = "/2/media/subtitles"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -465,12 +462,12 @@ def test_get_by_keys_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_by_keys: {e}")
+ pytest.fail(f"Contract test failed for delete_subtitles: {e}")
- def test_get_by_keys_required_parameters(self):
- """Test that get_by_keys handles parameters correctly."""
- method = getattr(self.media_client, "get_by_keys")
+ 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)
@@ -478,14 +475,14 @@ def test_get_by_keys_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_by_keys_response_structure(self):
- """Test get_by_keys 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 = {
@@ -495,13 +492,16 @@ def test_get_by_keys_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["media_keys"] = ["test"]
# Add request body if required
+ # Import and create proper request model instance
+ from xdk.media.models import DeleteSubtitlesRequest
+ # Create instance with minimal valid data (empty instance should work for most cases)
+ kwargs["body"] = DeleteSubtitlesRequest()
# Call method and verify response structure
- method = getattr(self.media_client, "get_by_keys")
+ 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
@@ -513,8 +513,8 @@ def test_get_by_keys_response_structure(self):
)
- def test_get_by_key_request_structure(self):
- """Test get_by_key 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()
@@ -523,15 +523,18 @@ def test_get_by_key_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_key"] = "test_value"
# Add request body if required
+ # Import and create proper request model instance
+ from xdk.media.models import InitializeUploadRequest
+ # Create instance with minimal valid data (empty instance should work for most cases)
+ kwargs["body"] = InitializeUploadRequest()
# Call the method
try:
- method = getattr(self.media_client, "get_by_key")
+ method = getattr(self.media_client, "initialize_upload")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -550,7 +553,7 @@ def test_get_by_key_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -559,14 +562,14 @@ def test_get_by_key_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/{media_key}"
+ expected_path = "/2/media/upload/initialize"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -582,12 +585,12 @@ def test_get_by_key_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_by_key: {e}")
+ pytest.fail(f"Contract test failed for initialize_upload: {e}")
- def test_get_by_key_required_parameters(self):
- """Test that get_by_key handles parameters correctly."""
- method = getattr(self.media_client, "get_by_key")
+ 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)
@@ -595,14 +598,14 @@ def test_get_by_key_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_by_key_response_structure(self):
- """Test get_by_key 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 = {
@@ -612,13 +615,16 @@ def test_get_by_key_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_key"] = "test"
# Add request body if required
+ # Import and create proper request model instance
+ from xdk.media.models import InitializeUploadRequest
+ # Create instance with minimal valid data (empty instance should work for most cases)
+ kwargs["body"] = InitializeUploadRequest()
# Call method and verify response structure
- method = getattr(self.media_client, "get_by_key")
+ 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
@@ -630,8 +636,8 @@ def test_get_by_key_response_structure(self):
)
- def test_finalize_upload_request_structure(self):
- """Test finalize_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()
@@ -640,15 +646,15 @@ def test_finalize_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
# Call the method
try:
- method = getattr(self.media_client, "finalize_upload")
+ method = getattr(self.media_client, "get_by_keys")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -667,7 +673,7 @@ def test_finalize_upload_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -676,14 +682,14 @@ def test_finalize_upload_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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}/finalize"
+ expected_path = "/2/media"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -699,12 +705,12 @@ def test_finalize_upload_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for finalize_upload: {e}")
+ pytest.fail(f"Contract test failed for get_by_keys: {e}")
- def test_finalize_upload_required_parameters(self):
- """Test that finalize_upload handles parameters correctly."""
- method = getattr(self.media_client, "finalize_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)
@@ -712,14 +718,14 @@ def test_finalize_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_finalize_upload_response_structure(self):
- """Test finalize_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 = {
@@ -729,13 +735,13 @@ def test_finalize_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
# Call method and verify response structure
- method = getattr(self.media_client, "finalize_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
@@ -872,8 +878,8 @@ def test_append_upload_response_structure(self):
)
- def test_initialize_upload_request_structure(self):
- """Test initialize_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()
@@ -888,12 +894,12 @@ def test_initialize_upload_request_structure(self):
# Add required parameters
# Add request body if required
# Import and create proper request model instance
- from xdk.media.models import InitializeUploadRequest
+ from xdk.media.models import CreateMetadataRequest
# Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = InitializeUploadRequest()
+ kwargs["body"] = CreateMetadataRequest()
# Call the method
try:
- method = getattr(self.media_client, "initialize_upload")
+ method = getattr(self.media_client, "create_metadata")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -928,7 +934,7 @@ def test_initialize_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/metadata"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -944,12 +950,12 @@ def test_initialize_upload_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for initialize_upload: {e}")
+ pytest.fail(f"Contract test failed for create_metadata: {e}")
- def test_initialize_upload_required_parameters(self):
- """Test that initialize_upload handles parameters correctly."""
- method = getattr(self.media_client, "initialize_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)
@@ -963,8 +969,8 @@ def test_initialize_upload_required_parameters(self):
method()
- def test_initialize_upload_response_structure(self):
- """Test initialize_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 = {
@@ -979,11 +985,11 @@ def test_initialize_upload_response_structure(self):
kwargs = {}
# Add request body if required
# Import and create proper request model instance
- from xdk.media.models import InitializeUploadRequest
+ from xdk.media.models import CreateMetadataRequest
# Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = InitializeUploadRequest()
+ kwargs["body"] = CreateMetadataRequest()
# Call method and verify response structure
- method = getattr(self.media_client, "initialize_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
@@ -995,8 +1001,8 @@ def test_initialize_upload_response_structure(self):
)
- def test_create_metadata_request_structure(self):
- """Test create_metadata 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()
@@ -1009,14 +1015,11 @@ def test_create_metadata_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, "create_metadata")
+ method = getattr(self.media_client, "finalize_upload")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1051,7 +1054,7 @@ def test_create_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/{id}/finalize"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1067,12 +1070,12 @@ def test_create_metadata_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for create_metadata: {e}")
+ pytest.fail(f"Contract test failed for finalize_upload: {e}")
- def test_create_metadata_required_parameters(self):
- """Test that create_metadata handles parameters correctly."""
- method = getattr(self.media_client, "create_metadata")
+ 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)
@@ -1086,8 +1089,8 @@ def test_create_metadata_required_parameters(self):
method()
- def test_create_metadata_response_structure(self):
- """Test create_metadata 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 = {
@@ -1100,13 +1103,10 @@ def test_create_metadata_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, "create_metadata")
+ 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
@@ -1118,8 +1118,8 @@ def test_create_metadata_response_structure(self):
)
- def test_get_upload_status_request_structure(self):
- """Test get_upload_status 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()
@@ -1132,11 +1132,11 @@ def test_get_upload_status_request_structure(self):
# Prepare test parameters
kwargs = {}
# Add required parameters
- kwargs["media_id"] = "test_value"
+ kwargs["media_key"] = "test_value"
# Add request body if required
# Call the method
try:
- method = getattr(self.media_client, "get_upload_status")
+ method = getattr(self.media_client, "get_by_key")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1171,7 +1171,7 @@ def test_get_upload_status_request_structure(self):
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/{media_key}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1187,12 +1187,12 @@ def test_get_upload_status_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_upload_status: {e}")
+ pytest.fail(f"Contract test failed for get_by_key: {e}")
- def test_get_upload_status_required_parameters(self):
- """Test that get_upload_status handles parameters correctly."""
- method = getattr(self.media_client, "get_upload_status")
+ 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)
@@ -1206,8 +1206,8 @@ def test_get_upload_status_required_parameters(self):
method()
- def test_get_upload_status_response_structure(self):
- """Test get_upload_status 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 = {
@@ -1220,10 +1220,10 @@ def test_get_upload_status_response_structure(self):
mock_session.get.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
- kwargs["media_id"] = "test"
+ kwargs["media_key"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.media_client, "get_upload_status")
+ 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
@@ -1235,8 +1235,8 @@ def test_get_upload_status_response_structure(self):
)
- def test_upload_request_structure(self):
- """Test upload 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()
@@ -1245,18 +1245,18 @@ def test_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_keys"] = ["test_item"]
+ kwargs["end_time"] = "test_end_time"
+ kwargs["start_time"] = "test_start_time"
+ kwargs["granularity"] = "test_granularity"
# Add request body if required
- # Import and create proper request model instance
- from xdk.media.models import UploadRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = UploadRequest()
# Call the method
try:
- method = getattr(self.media_client, "upload")
+ method = getattr(self.media_client, "get_analytics")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1275,7 +1275,7 @@ def test_upload_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -1284,14 +1284,14 @@ def test_upload_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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"
+ expected_path = "/2/media/analytics"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1307,12 +1307,12 @@ def test_upload_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for upload: {e}")
+ pytest.fail(f"Contract test failed for get_analytics: {e}")
- def test_upload_required_parameters(self):
- """Test that upload handles parameters correctly."""
- method = getattr(self.media_client, "upload")
+ 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)
@@ -1320,14 +1320,14 @@ def test_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_upload_response_structure(self):
- """Test upload 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 = {
@@ -1337,16 +1337,16 @@ def test_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_keys"] = ["test"]
+ kwargs["end_time"] = "test_value"
+ kwargs["start_time"] = "test_value"
+ kwargs["granularity"] = "test_value"
# Add request body if required
- # Import and create proper request model instance
- from xdk.media.models import UploadRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = UploadRequest()
# Call method and verify response structure
- method = getattr(self.media_client, "upload")
+ 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
diff --git a/xdk/python/tests/media/test_structure.py b/xdk/python/tests/media/test_structure.py
index 07d8516e..71deb852 100644
--- a/xdk/python/tests/media/test_structure.py
+++ b/xdk/python/tests/media/test_structure.py
@@ -28,33 +28,37 @@ def setup_class(self):
self.media_client = getattr(self.client, "media")
- def test_create_subtitles_exists(self):
- """Test that create_subtitles 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, "create_subtitles", None)
+ method = getattr(MediaClient, "get_upload_status", None)
assert (
method is not None
- ), f"Method create_subtitles does not exist on MediaClient"
+ ), f"Method get_upload_status does not exist on MediaClient"
# Check method is callable
- assert callable(method), f"create_subtitles 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"create_subtitles should have at least 'self' parameter"
+ ), 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 create_subtitles"
+ ), 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]
@@ -63,32 +67,28 @@ def test_create_subtitles_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_create_subtitles_return_annotation(self):
- """Test that create_subtitles has proper return type annotation."""
- method = getattr(MediaClient, "create_subtitles")
+ 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 create_subtitles should have return type annotation"
+ ), f"Method get_upload_status should have return type annotation"
- def test_delete_subtitles_exists(self):
- """Test that delete_subtitles method exists with correct signature."""
+ def test_upload_exists(self):
+ """Test that upload method exists with correct signature."""
# Check method exists
- method = getattr(MediaClient, "delete_subtitles", None)
- assert (
- method is not None
- ), f"Method delete_subtitles 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"delete_subtitles 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"delete_subtitles 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]}'"
@@ -97,7 +97,7 @@ def test_delete_subtitles_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from delete_subtitles"
+ ), f"Required parameter '{required_param}' missing from upload"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -108,46 +108,43 @@ def test_delete_subtitles_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_delete_subtitles_return_annotation(self):
- """Test that delete_subtitles has proper return type annotation."""
- method = getattr(MediaClient, "delete_subtitles")
+ 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 delete_subtitles should have return type annotation"
+ ), f"Method upload should have return type annotation"
- def test_get_analytics_exists(self):
- """Test that get_analytics 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, "get_analytics", None)
- assert method is not None, f"Method get_analytics does not exist on MediaClient"
+ method = getattr(MediaClient, "create_subtitles", None)
+ assert (
+ method is not None
+ ), f"Method create_subtitles does not exist on MediaClient"
# Check method is callable
- assert callable(method), f"get_analytics 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"get_analytics should have at least 'self' parameter"
+ assert (
+ len(params) >= 1
+ ), f"create_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 = [
- "media_keys",
- "end_time",
- "start_time",
- "granularity",
- ]
+ required_params = []
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_analytics"
+ ), f"Required parameter '{required_param}' missing from create_subtitles"
# Check optional parameters have defaults (excluding 'self')
- optional_params = [
- "media_analytics.fields",
- ]
+ optional_params = []
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -156,43 +153,43 @@ def test_get_analytics_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_analytics_return_annotation(self):
- """Test that get_analytics has proper return type annotation."""
- method = getattr(MediaClient, "get_analytics")
+ 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 get_analytics should have return type annotation"
+ ), f"Method create_subtitles should have return type annotation"
- def test_get_by_keys_exists(self):
- """Test that get_by_keys 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, "get_by_keys", None)
- assert method is not None, f"Method get_by_keys does not exist on MediaClient"
+ method = getattr(MediaClient, "delete_subtitles", None)
+ assert (
+ method is not None
+ ), f"Method delete_subtitles does not exist on MediaClient"
# Check method is callable
- assert callable(method), f"get_by_keys 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"get_by_keys should have at least 'self' parameter"
+ assert (
+ len(params) >= 1
+ ), f"delete_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 = [
- "media_keys",
- ]
+ required_params = []
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_by_keys"
+ ), f"Required parameter '{required_param}' missing from delete_subtitles"
# Check optional parameters have defaults (excluding 'self')
- optional_params = [
- "media.fields",
- ]
+ optional_params = []
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -201,43 +198,43 @@ def test_get_by_keys_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_by_keys_return_annotation(self):
- """Test that get_by_keys has proper return type annotation."""
- method = getattr(MediaClient, "get_by_keys")
+ 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 get_by_keys should have return type annotation"
+ ), f"Method delete_subtitles should have return type annotation"
- def test_get_by_key_exists(self):
- """Test that get_by_key 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, "get_by_key", None)
- assert method is not None, f"Method get_by_key does not exist on MediaClient"
+ method = getattr(MediaClient, "initialize_upload", None)
+ assert (
+ method is not None
+ ), f"Method initialize_upload does not exist on MediaClient"
# Check method is callable
- assert callable(method), f"get_by_key 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"get_by_key should have at least 'self' parameter"
+ assert (
+ len(params) >= 1
+ ), f"initialize_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_key",
- ]
+ required_params = []
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_by_key"
+ ), f"Required parameter '{required_param}' missing from initialize_upload"
# Check optional parameters have defaults (excluding 'self')
- optional_params = [
- "media.fields",
- ]
+ optional_params = []
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -246,45 +243,43 @@ def test_get_by_key_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_by_key_return_annotation(self):
- """Test that get_by_key has proper return type annotation."""
- method = getattr(MediaClient, "get_by_key")
+ 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 get_by_key should have return type annotation"
+ ), f"Method initialize_upload should have return type annotation"
- def test_finalize_upload_exists(self):
- """Test that finalize_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, "finalize_upload", None)
- assert (
- method is not None
- ), f"Method finalize_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"finalize_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"finalize_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 finalize_upload"
+ ), f"Required parameter '{required_param}' missing from get_by_keys"
# Check optional parameters have defaults (excluding 'self')
- optional_params = []
+ optional_params = [
+ "media.fields",
+ ]
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -293,14 +288,14 @@ def test_finalize_upload_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_finalize_upload_return_annotation(self):
- """Test that finalize_upload has proper return type annotation."""
- method = getattr(MediaClient, "finalize_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 finalize_upload should have return type annotation"
+ ), f"Method get_by_keys should have return type annotation"
def test_append_upload_exists(self):
@@ -346,22 +341,22 @@ def test_append_upload_return_annotation(self):
), f"Method append_upload should have return type annotation"
- def test_initialize_upload_exists(self):
- """Test that initialize_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, "initialize_upload", None)
+ method = getattr(MediaClient, "create_metadata", None)
assert (
method is not None
- ), f"Method initialize_upload does not exist on MediaClient"
+ ), f"Method create_metadata does not exist on MediaClient"
# Check method is callable
- assert callable(method), f"initialize_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"initialize_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]}'"
@@ -370,7 +365,7 @@ def test_initialize_upload_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from initialize_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:
@@ -381,41 +376,43 @@ def test_initialize_upload_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_initialize_upload_return_annotation(self):
- """Test that initialize_upload has proper return type annotation."""
- method = getattr(MediaClient, "initialize_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 initialize_upload should have return type annotation"
+ ), f"Method create_metadata should have return type annotation"
- def test_create_metadata_exists(self):
- """Test that create_metadata 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, "create_metadata", None)
+ method = getattr(MediaClient, "finalize_upload", None)
assert (
method is not None
- ), f"Method create_metadata does not exist on MediaClient"
+ ), f"Method finalize_upload does not exist on MediaClient"
# Check method is callable
- assert callable(method), f"create_metadata 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"create_metadata 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 = []
+ required_params = [
+ "id",
+ ]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from create_metadata"
+ ), f"Required parameter '{required_param}' missing from finalize_upload"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -426,46 +423,42 @@ def test_create_metadata_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_create_metadata_return_annotation(self):
- """Test that create_metadata has proper return type annotation."""
- method = getattr(MediaClient, "create_metadata")
+ 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 create_metadata should have return type annotation"
+ ), f"Method finalize_upload should have return type annotation"
- def test_get_upload_status_exists(self):
- """Test that get_upload_status 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_upload_status", None)
- assert (
- method is not None
- ), f"Method get_upload_status 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_upload_status 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_upload_status 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]}'"
# Check required parameters exist (excluding 'self')
required_params = [
- "media_id",
+ "media_key",
]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_upload_status"
+ ), f"Required parameter '{required_param}' missing from get_by_key"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "command",
+ "media.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -475,39 +468,46 @@ def test_get_upload_status_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_upload_status_return_annotation(self):
- """Test that get_upload_status has proper return type annotation."""
- method = getattr(MediaClient, "get_upload_status")
+ 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_upload_status should have return type annotation"
+ ), f"Method get_by_key should have return type annotation"
- def test_upload_exists(self):
- """Test that upload 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, "upload", None)
- assert method is not None, f"Method upload 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"upload 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"upload 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 = []
+ 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 upload"
+ ), f"Required parameter '{required_param}' missing from get_analytics"
# Check optional parameters have defaults (excluding 'self')
- optional_params = []
+ optional_params = [
+ "media_analytics.fields",
+ ]
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -516,30 +516,30 @@ def test_upload_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_upload_return_annotation(self):
- """Test that upload has proper return type annotation."""
- method = getattr(MediaClient, "upload")
+ 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 upload should have return type annotation"
+ ), f"Method get_analytics should have return type annotation"
def test_all_expected_methods_exist(self):
"""Test that all expected methods exist on the client."""
expected_methods = [
+ "get_upload_status",
+ "upload",
"create_subtitles",
"delete_subtitles",
- "get_analytics",
+ "initialize_upload",
"get_by_keys",
- "get_by_key",
- "finalize_upload",
"append_upload",
- "initialize_upload",
"create_metadata",
- "get_upload_status",
- "upload",
+ "finalize_upload",
+ "get_by_key",
+ "get_analytics",
]
for expected_method in expected_methods:
assert hasattr(
diff --git a/xdk/python/tests/news/__init__.py b/xdk/python/tests/news/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/xdk/python/tests/news/test_contracts.py b/xdk/python/tests/news/test_contracts.py
new file mode 100644
index 00000000..964ac823
--- /dev/null
+++ b/xdk/python/tests/news/test_contracts.py
@@ -0,0 +1,261 @@
+# AUTO-GENERATED FILE - DO NOT EDIT
+# This file was automatically generated by the XDK build tool.
+# Any manual changes will be overwritten on the next generation.
+"""
+Auto-generated contract tests for {"class_name": "News", "display_name": "news", "import_name": "news", "original": ["news"], "property_name": "news"} client.
+
+This module contains tests that validate the request/response contracts
+of the {"class_name": "News", "display_name": "news", "import_name": "news", "original": ["news"], "property_name": "news"} client against the OpenAPI specification.
+
+Generated automatically - do not edit manually.
+"""
+
+import pytest
+import json
+from unittest.mock import Mock, patch
+from xdk.news.client import NewsClient
+from xdk import Client
+
+
+class TestNewsContracts:
+ """Test the API contracts of NewsClient."""
+
+
+ def setup_class(self):
+ """Set up test fixtures."""
+ self.client = Client(base_url="https://api.example.com")
+ self.news_client = getattr(self.client, "news")
+
+
+ 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()
+ 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.news_client, "search")
+ result = method(**kwargs)
+ # Check if this is a streaming operation (returns Generator)
+ import types
+ is_streaming = isinstance(result, types.GeneratorType)
+ if is_streaming:
+ # For streaming operations, we need to set up the mock to handle streaming
+ # Mock the streaming response
+ mock_streaming_response = Mock()
+ mock_streaming_response.status_code = 200
+ mock_streaming_response.raise_for_status.return_value = None
+ mock_streaming_response.__enter__ = Mock(
+ return_value=mock_streaming_response
+ )
+ mock_streaming_response.__exit__ = Mock(return_value=None)
+ # Mock iter_content to yield some test data
+ test_data = '{"data": "test"}\n'
+ mock_streaming_response.iter_content.return_value = [test_data]
+ # Update the session mock to return our streaming response
+ mock_session.get.return_value = mock_streaming_response
+ # Consume the generator to trigger the HTTP request
+ try:
+ next(result)
+ except StopIteration:
+ pass # Expected when stream ends
+ except Exception:
+ pass # Ignore other exceptions in test data processing
+ # 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/news/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
+ if is_streaming:
+ # For streaming, verify we got a generator
+ assert isinstance(
+ result, types.GeneratorType
+ ), "Streaming method should return a generator"
+ else:
+ # For regular operations, verify we got a result
+ assert result is not None, "Method should return a result"
+ except Exception as e:
+ pytest.fail(f"Contract test failed for search: {e}")
+
+
+ def test_search_required_parameters(self):
+ """Test that search handles parameters correctly."""
+ method = getattr(self.news_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)
+ 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_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 = {
+ "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.news_client, "search")
+ 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_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()
+ 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.news_client, "get")
+ result = method(**kwargs)
+ # Check if this is a streaming operation (returns Generator)
+ import types
+ is_streaming = isinstance(result, types.GeneratorType)
+ if is_streaming:
+ # For streaming operations, we need to set up the mock to handle streaming
+ # Mock the streaming response
+ mock_streaming_response = Mock()
+ mock_streaming_response.status_code = 200
+ mock_streaming_response.raise_for_status.return_value = None
+ mock_streaming_response.__enter__ = Mock(
+ return_value=mock_streaming_response
+ )
+ mock_streaming_response.__exit__ = Mock(return_value=None)
+ # Mock iter_content to yield some test data
+ test_data = '{"data": "test"}\n'
+ mock_streaming_response.iter_content.return_value = [test_data]
+ # Update the session mock to return our streaming response
+ mock_session.get.return_value = mock_streaming_response
+ # Consume the generator to trigger the HTTP request
+ try:
+ next(result)
+ except StopIteration:
+ pass # Expected when stream ends
+ except Exception:
+ pass # Ignore other exceptions in test data processing
+ # 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/news/{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
+ if is_streaming:
+ # For streaming, verify we got a generator
+ assert isinstance(
+ result, types.GeneratorType
+ ), "Streaming method should return a generator"
+ else:
+ # For regular operations, verify we got a result
+ assert result is not None, "Method should return a result"
+ except Exception as e:
+ pytest.fail(f"Contract test failed for get: {e}")
+
+
+ def test_get_required_parameters(self):
+ """Test that get handles parameters correctly."""
+ method = getattr(self.news_client, "get")
+ # 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_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 = {
+ "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.news_client, "get")
+ 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/news/test_generic.py b/xdk/python/tests/news/test_generic.py
new file mode 100644
index 00000000..04ad662d
--- /dev/null
+++ b/xdk/python/tests/news/test_generic.py
@@ -0,0 +1,125 @@
+# AUTO-GENERATED FILE - DO NOT EDIT
+# This file was automatically generated by the XDK build tool.
+# Any manual changes will be overwritten on the next generation.
+"""
+Auto-generated generic tests for {"class_name": "News", "display_name": "news", "import_name": "news", "original": ["news"], "property_name": "news"} client.
+
+This module contains general tests that validate the overall client
+functionality, imports, error handling, and common behavior patterns
+that apply across all operations without being operation-specific.
+
+Generated automatically - do not edit manually.
+"""
+
+import pytest
+import inspect
+from unittest.mock import Mock, patch
+from xdk.news.client import NewsClient
+from xdk import Client
+
+
+class TestNewsGeneric:
+ """Generic tests for NewsClient."""
+
+
+ def setup_class(self):
+ """Set up test fixtures."""
+ self.client = Client(base_url="https://api.example.com")
+ self.news_client = getattr(self.client, "news")
+
+
+ def test_client_exists(self):
+ """Test that NewsClient class exists and is importable."""
+ assert NewsClient is not None
+ assert hasattr(NewsClient, "__name__")
+ assert NewsClient.__name__ == "NewsClient"
+
+
+ def test_client_initialization(self):
+ """Test that NewsClient can be initialized properly."""
+ assert self.news_client is not None
+ assert isinstance(self.news_client, NewsClient)
+
+
+ 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(NewsClient)
+ if not name.startswith("_") and callable(getattr(NewsClient, name))
+ ]
+ if client_methods:
+ method_name = client_methods[0]
+ method = getattr(self.news_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, "news")
+ # Client should have standard Python object features
+ assert hasattr(self.news_client, "__class__")
+ assert hasattr(self.news_client, "__dict__")
+ # Should have at least one public method
+ public_methods = [
+ name
+ for name in dir(self.news_client)
+ if not name.startswith("_") and callable(getattr(self.news_client, name))
+ ]
+ assert (
+ len(public_methods) > 0
+ ), f"NewsClient 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(NewsClient)
+ if not name.startswith("_") and callable(getattr(NewsClient, name))
+ ]
+ for method_name in public_methods:
+ method = getattr(NewsClient, 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/news/test_structure.py b/xdk/python/tests/news/test_structure.py
new file mode 100644
index 00000000..53e0a39d
--- /dev/null
+++ b/xdk/python/tests/news/test_structure.py
@@ -0,0 +1,135 @@
+# AUTO-GENERATED FILE - DO NOT EDIT
+# This file was automatically generated by the XDK build tool.
+# Any manual changes will be overwritten on the next generation.
+"""
+Auto-generated structural tests for {"class_name": "News", "display_name": "news", "import_name": "news", "original": ["news"], "property_name": "news"} client.
+
+This module contains tests that validate the structure and API surface
+of the {"class_name": "News", "display_name": "news", "import_name": "news", "original": ["news"], "property_name": "news"} client. These tests ensure that all expected methods
+exist, have correct signatures, and proper type annotations for robust API contracts.
+
+Generated automatically - do not edit manually.
+"""
+
+import pytest
+import inspect
+from typing import get_type_hints
+from xdk.news.client import NewsClient
+from xdk import Client
+
+
+class TestNewsStructure:
+ """Test the structure of NewsClient."""
+
+
+ def setup_class(self):
+ """Set up test fixtures."""
+ self.client = Client(base_url="https://api.example.com")
+ self.news_client = getattr(self.client, "news")
+
+
+ def test_search_exists(self):
+ """Test that search method exists with correct signature."""
+ # Check method exists
+ method = getattr(NewsClient, "search", None)
+ assert method is not None, f"Method search does not exist on NewsClient"
+ # Check method is 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"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 = [
+ "query",
+ ]
+ for required_param in required_params:
+ assert (
+ required_param in params
+ ), f"Required parameter '{required_param}' missing from search"
+ # Check optional parameters have defaults (excluding 'self')
+ optional_params = [
+ "max_results",
+ "max_age_hours",
+ "news.fields",
+ ]
+ 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_return_annotation(self):
+ """Test that search has proper return type annotation."""
+ method = getattr(NewsClient, "search")
+ sig = inspect.signature(method)
+ # Check return annotation exists
+ assert (
+ sig.return_annotation is not inspect.Signature.empty
+ ), f"Method search should have return type annotation"
+
+
+ def test_get_exists(self):
+ """Test that get method exists with correct signature."""
+ # Check method exists
+ method = getattr(NewsClient, "get", None)
+ assert method is not None, f"Method get does not exist on NewsClient"
+ # Check method is 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 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"
+ # Check optional parameters have defaults (excluding 'self')
+ optional_params = [
+ "news.fields",
+ ]
+ 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_return_annotation(self):
+ """Test that get has proper return type annotation."""
+ method = getattr(NewsClient, "get")
+ sig = inspect.signature(method)
+ # Check return annotation exists
+ assert (
+ sig.return_annotation is not inspect.Signature.empty
+ ), 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 = [
+ "search",
+ "get",
+ ]
+ for expected_method in expected_methods:
+ assert hasattr(
+ NewsClient, expected_method
+ ), f"Expected method '{expected_method}' not found on NewsClient"
+ assert callable(
+ getattr(NewsClient, expected_method)
+ ), f"'{expected_method}' exists but is not callable"
diff --git a/xdk/python/tests/posts/test_contracts.py b/xdk/python/tests/posts/test_contracts.py
index 571a613e..78f38f59 100644
--- a/xdk/python/tests/posts/test_contracts.py
+++ b/xdk/python/tests/posts/test_contracts.py
@@ -144,8 +144,8 @@ def test_get_quoted_response_structure(self):
)
- def test_get_counts_all_request_structure(self):
- """Test get_counts_all 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()
@@ -158,11 +158,14 @@ def test_get_counts_all_request_structure(self):
# Prepare test parameters
kwargs = {}
# Add required parameters
- kwargs["query"] = "test_query"
+ 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.posts_client, "get_counts_all")
+ method = getattr(self.posts_client, "get_analytics")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -197,7 +200,7 @@ def test_get_counts_all_request_structure(self):
called_url = (
call_args[0][0] if call_args[0] else call_args[1].get("url", "")
)
- expected_path = "/2/tweets/counts/all"
+ expected_path = "/2/tweets/analytics"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -213,12 +216,12 @@ def test_get_counts_all_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_counts_all: {e}")
+ pytest.fail(f"Contract test failed for get_analytics: {e}")
- def test_get_counts_all_required_parameters(self):
- """Test that get_counts_all handles parameters correctly."""
- method = getattr(self.posts_client, "get_counts_all")
+ 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)
@@ -232,8 +235,8 @@ def test_get_counts_all_required_parameters(self):
method()
- def test_get_counts_all_response_structure(self):
- """Test get_counts_all 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 = {
@@ -246,10 +249,13 @@ def test_get_counts_all_response_structure(self):
mock_session.get.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
- kwargs["query"] = "test_value"
+ 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.posts_client, "get_counts_all")
+ 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
@@ -261,8 +267,8 @@ def test_get_counts_all_response_structure(self):
)
- def test_get_by_id_request_structure(self):
- """Test get_by_id 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()
@@ -271,15 +277,19 @@ def test_get_by_id_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["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.posts_client, "get_by_id")
+ method = getattr(self.posts_client, "hide_reply")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -298,7 +308,7 @@ def test_get_by_id_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.put.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -307,14 +317,14 @@ def test_get_by_id_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/tweets/{id}"
+ expected_path = "/2/tweets/{tweet_id}/hidden"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -330,12 +340,12 @@ def test_get_by_id_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_by_id: {e}")
+ pytest.fail(f"Contract test failed for hide_reply: {e}")
- def test_get_by_id_required_parameters(self):
- """Test that get_by_id handles parameters correctly."""
- method = getattr(self.posts_client, "get_by_id")
+ 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)
@@ -343,14 +353,14 @@ def test_get_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.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_get_by_id_response_structure(self):
- """Test get_by_id 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 = {
@@ -360,13 +370,17 @@ def test_get_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.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.posts_client, "get_by_id")
+ 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
@@ -378,8 +392,8 @@ def test_get_by_id_response_structure(self):
)
- def test_delete_request_structure(self):
- """Test delete 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()
@@ -388,7 +402,7 @@ def test_delete_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
@@ -396,7 +410,7 @@ def test_delete_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.posts_client, "delete")
+ method = getattr(self.posts_client, "get_reposted_by")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -415,7 +429,7 @@ def test_delete_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.delete.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -424,14 +438,14 @@ def test_delete_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/tweets/{id}"
+ expected_path = "/2/tweets/{id}/retweeted_by"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -447,12 +461,12 @@ def test_delete_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for delete: {e}")
+ pytest.fail(f"Contract test failed for get_reposted_by: {e}")
- def test_delete_required_parameters(self):
- """Test that delete handles parameters correctly."""
- method = getattr(self.posts_client, "delete")
+ 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)
@@ -460,14 +474,14 @@ def test_delete_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_delete_response_structure(self):
- """Test delete 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 = {
@@ -477,13 +491,13 @@ def test_delete_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"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.posts_client, "delete")
+ 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
@@ -495,8 +509,8 @@ def test_delete_response_structure(self):
)
- def test_get_insights28hr_request_structure(self):
- """Test get_insights28hr 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()
@@ -509,13 +523,11 @@ def test_get_insights28hr_request_structure(self):
# Prepare test parameters
kwargs = {}
# Add required parameters
- kwargs["tweet_ids"] = ["test_item"]
- kwargs["granularity"] = "test_granularity"
- kwargs["requested_metrics"] = ["test_item"]
+ kwargs["id"] = "test_value"
# Add request body if required
# Call the method
try:
- method = getattr(self.posts_client, "get_insights28hr")
+ method = getattr(self.posts_client, "get_reposts")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -550,7 +562,7 @@ def test_get_insights28hr_request_structure(self):
called_url = (
call_args[0][0] if call_args[0] else call_args[1].get("url", "")
)
- expected_path = "/2/insights/28hr"
+ expected_path = "/2/tweets/{id}/retweets"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -566,12 +578,12 @@ def test_get_insights28hr_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_insights28hr: {e}")
+ pytest.fail(f"Contract test failed for get_reposts: {e}")
- def test_get_insights28hr_required_parameters(self):
- """Test that get_insights28hr handles parameters correctly."""
- method = getattr(self.posts_client, "get_insights28hr")
+ 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)
@@ -585,8 +597,8 @@ def test_get_insights28hr_required_parameters(self):
method()
- def test_get_insights28hr_response_structure(self):
- """Test get_insights28hr 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 = {
@@ -599,12 +611,10 @@ def test_get_insights28hr_response_structure(self):
mock_session.get.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
- kwargs["tweet_ids"] = ["test"]
- kwargs["granularity"] = "test_value"
- kwargs["requested_metrics"] = ["test"]
+ kwargs["id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.posts_client, "get_insights28hr")
+ 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
@@ -616,8 +626,8 @@ def test_get_insights28hr_response_structure(self):
)
- def test_get_counts_recent_request_structure(self):
- """Test get_counts_recent 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()
@@ -630,11 +640,11 @@ def test_get_counts_recent_request_structure(self):
# Prepare test parameters
kwargs = {}
# Add required parameters
- kwargs["query"] = "test_query"
+ kwargs["ids"] = ["test_item"]
# Add request body if required
# Call the method
try:
- method = getattr(self.posts_client, "get_counts_recent")
+ method = getattr(self.posts_client, "get_by_ids")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -669,7 +679,7 @@ def test_get_counts_recent_request_structure(self):
called_url = (
call_args[0][0] if call_args[0] else call_args[1].get("url", "")
)
- expected_path = "/2/tweets/counts/recent"
+ expected_path = "/2/tweets"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -685,12 +695,12 @@ def test_get_counts_recent_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_counts_recent: {e}")
+ pytest.fail(f"Contract test failed for get_by_ids: {e}")
- def test_get_counts_recent_required_parameters(self):
- """Test that get_counts_recent handles parameters correctly."""
- method = getattr(self.posts_client, "get_counts_recent")
+ 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)
@@ -704,8 +714,8 @@ def test_get_counts_recent_required_parameters(self):
method()
- def test_get_counts_recent_response_structure(self):
- """Test get_counts_recent 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 = {
@@ -718,10 +728,10 @@ def test_get_counts_recent_response_structure(self):
mock_session.get.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
- kwargs["query"] = "test_value"
+ kwargs["ids"] = ["test"]
# Add request body if required
# Call method and verify response structure
- method = getattr(self.posts_client, "get_counts_recent")
+ 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
@@ -733,8 +743,8 @@ def test_get_counts_recent_response_structure(self):
)
- def test_search_all_request_structure(self):
- """Test search_all 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()
@@ -743,15 +753,18 @@ def test_search_all_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["query"] = "test_query"
# 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.posts_client, "search_all")
+ method = getattr(self.posts_client, "create")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -770,7 +783,7 @@ def test_search_all_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -779,14 +792,14 @@ def test_search_all_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/search/all"
+ expected_path = "/2/tweets"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -802,12 +815,12 @@ def test_search_all_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for search_all: {e}")
+ pytest.fail(f"Contract test failed for create: {e}")
- def test_search_all_required_parameters(self):
- """Test that search_all handles parameters correctly."""
- method = getattr(self.posts_client, "search_all")
+ 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)
@@ -815,14 +828,14 @@ def test_search_all_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_search_all_response_structure(self):
- """Test search_all 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 = {
@@ -832,13 +845,16 @@ def test_search_all_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["query"] = "test_value"
# 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.posts_client, "search_all")
+ 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
@@ -850,8 +866,8 @@ def test_search_all_response_structure(self):
)
- def test_get_reposted_by_request_structure(self):
- """Test get_reposted_by 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()
@@ -868,7 +884,7 @@ def test_get_reposted_by_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.posts_client, "get_reposted_by")
+ method = getattr(self.posts_client, "get_liking_users")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -903,7 +919,7 @@ def test_get_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/{id}/liking_users"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -919,12 +935,12 @@ def test_get_reposted_by_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_reposted_by: {e}")
+ pytest.fail(f"Contract test failed for get_liking_users: {e}")
- def test_get_reposted_by_required_parameters(self):
- """Test that get_reposted_by handles parameters correctly."""
- method = getattr(self.posts_client, "get_reposted_by")
+ 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)
@@ -938,8 +954,8 @@ def test_get_reposted_by_required_parameters(self):
method()
- def test_get_reposted_by_response_structure(self):
- """Test get_reposted_by 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 = {
@@ -955,7 +971,7 @@ def test_get_reposted_by_response_structure(self):
kwargs["id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.posts_client, "get_reposted_by")
+ 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
@@ -967,8 +983,8 @@ def test_get_reposted_by_response_structure(self):
)
- def test_search_recent_request_structure(self):
- """Test search_recent 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()
@@ -985,7 +1001,7 @@ def test_search_recent_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.posts_client, "search_recent")
+ method = getattr(self.posts_client, "get_counts_recent")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1020,7 +1036,7 @@ def test_search_recent_request_structure(self):
called_url = (
call_args[0][0] if call_args[0] else call_args[1].get("url", "")
)
- expected_path = "/2/tweets/search/recent"
+ expected_path = "/2/tweets/counts/recent"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1036,12 +1052,12 @@ def test_search_recent_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for search_recent: {e}")
+ pytest.fail(f"Contract test failed for get_counts_recent: {e}")
- def test_search_recent_required_parameters(self):
- """Test that search_recent handles parameters correctly."""
- method = getattr(self.posts_client, "search_recent")
+ 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)
@@ -1055,8 +1071,8 @@ def test_search_recent_required_parameters(self):
method()
- def test_search_recent_response_structure(self):
- """Test search_recent 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 = {
@@ -1072,7 +1088,7 @@ def test_search_recent_response_structure(self):
kwargs["query"] = "test_value"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.posts_client, "search_recent")
+ 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
@@ -1084,8 +1100,8 @@ def test_search_recent_response_structure(self):
)
- def test_get_insights_historical_request_structure(self):
- """Test get_insights_historical 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()
@@ -1098,15 +1114,11 @@ def test_get_insights_historical_request_structure(self):
# 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"]
+ kwargs["query"] = "test_query"
# Add request body if required
# Call the method
try:
- method = getattr(self.posts_client, "get_insights_historical")
+ method = getattr(self.posts_client, "get_counts_all")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1141,7 +1153,7 @@ def test_get_insights_historical_request_structure(self):
called_url = (
call_args[0][0] if call_args[0] else call_args[1].get("url", "")
)
- expected_path = "/2/insights/historical"
+ expected_path = "/2/tweets/counts/all"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1157,12 +1169,12 @@ def test_get_insights_historical_request_structure(self):
# For regular operations, verify we got a result
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}")
+ pytest.fail(f"Contract test failed for get_counts_all: {e}")
- def test_get_insights_historical_required_parameters(self):
- """Test that get_insights_historical handles parameters correctly."""
- method = getattr(self.posts_client, "get_insights_historical")
+ 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)
@@ -1176,8 +1188,8 @@ def test_get_insights_historical_required_parameters(self):
method()
- def test_get_insights_historical_response_structure(self):
- """Test get_insights_historical 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 = {
@@ -1190,14 +1202,10 @@ def test_get_insights_historical_response_structure(self):
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"]
+ kwargs["query"] = "test_value"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.posts_client, "get_insights_historical")
+ 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
@@ -1209,8 +1217,8 @@ def test_get_insights_historical_response_structure(self):
)
- def test_get_by_ids_request_structure(self):
- """Test get_by_ids 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()
@@ -1223,11 +1231,11 @@ def test_get_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.posts_client, "get_by_ids")
+ method = getattr(self.posts_client, "search_all")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1262,7 +1270,7 @@ def test_get_by_ids_request_structure(self):
called_url = (
call_args[0][0] if call_args[0] else call_args[1].get("url", "")
)
- expected_path = "/2/tweets"
+ expected_path = "/2/tweets/search/all"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1278,12 +1286,12 @@ def test_get_by_ids_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_by_ids: {e}")
+ pytest.fail(f"Contract test failed for search_all: {e}")
- def test_get_by_ids_required_parameters(self):
- """Test that get_by_ids handles parameters correctly."""
- method = getattr(self.posts_client, "get_by_ids")
+ 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)
@@ -1297,8 +1305,8 @@ def test_get_by_ids_required_parameters(self):
method()
- def test_get_by_ids_response_structure(self):
- """Test get_by_ids 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 = {
@@ -1311,10 +1319,10 @@ def test_get_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.posts_client, "get_by_ids")
+ 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
@@ -1326,8 +1334,8 @@ def test_get_by_ids_response_structure(self):
)
- def test_create_request_structure(self):
- """Test create 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()
@@ -1336,18 +1344,15 @@ def test_create_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["query"] = "test_query"
# 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.posts_client, "create")
+ method = getattr(self.posts_client, "search_recent")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1366,7 +1371,7 @@ def test_create_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -1375,14 +1380,14 @@ def test_create_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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"
+ expected_path = "/2/tweets/search/recent"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1398,12 +1403,12 @@ def test_create_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for create: {e}")
+ pytest.fail(f"Contract test failed for search_recent: {e}")
- def test_create_required_parameters(self):
- """Test that create handles parameters correctly."""
- method = getattr(self.posts_client, "create")
+ 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)
@@ -1411,14 +1416,14 @@ def test_create_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_response_structure(self):
- """Test create 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 = {
@@ -1428,16 +1433,13 @@ def test_create_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["query"] = "test_value"
# 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.posts_client, "create")
+ 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
@@ -1449,8 +1451,8 @@ def test_create_response_structure(self):
)
- def test_get_liking_users_request_structure(self):
- """Test get_liking_users 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()
@@ -1463,11 +1465,15 @@ def test_get_liking_users_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.posts_client, "get_liking_users")
+ method = getattr(self.posts_client, "get_insights_historical")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1502,7 +1508,7 @@ def test_get_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/insights/historical"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1518,12 +1524,12 @@ def test_get_liking_users_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_liking_users: {e}")
+ pytest.fail(f"Contract test failed for get_insights_historical: {e}")
- def test_get_liking_users_required_parameters(self):
- """Test that get_liking_users handles parameters correctly."""
- method = getattr(self.posts_client, "get_liking_users")
+ 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)
@@ -1537,8 +1543,8 @@ def test_get_liking_users_required_parameters(self):
method()
- def test_get_liking_users_response_structure(self):
- """Test get_liking_users 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 = {
@@ -1551,10 +1557,14 @@ def test_get_liking_users_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.posts_client, "get_liking_users")
+ 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
@@ -1566,8 +1576,8 @@ def test_get_liking_users_response_structure(self):
)
- def test_get_analytics_request_structure(self):
- """Test get_analytics 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()
@@ -1580,14 +1590,11 @@ def test_get_analytics_request_structure(self):
# 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"
+ kwargs["id"] = "test_value"
# Add request body if required
# Call the method
try:
- method = getattr(self.posts_client, "get_analytics")
+ method = getattr(self.posts_client, "get_by_id")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1622,7 +1629,7 @@ def test_get_analytics_request_structure(self):
called_url = (
call_args[0][0] if call_args[0] else call_args[1].get("url", "")
)
- expected_path = "/2/tweets/analytics"
+ expected_path = "/2/tweets/{id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1638,12 +1645,12 @@ def test_get_analytics_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_analytics: {e}")
+ pytest.fail(f"Contract test failed for get_by_id: {e}")
- def test_get_analytics_required_parameters(self):
- """Test that get_analytics handles parameters correctly."""
- method = getattr(self.posts_client, "get_analytics")
+ 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)
@@ -1657,8 +1664,8 @@ def test_get_analytics_required_parameters(self):
method()
- def test_get_analytics_response_structure(self):
- """Test get_analytics 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 = {
@@ -1671,13 +1678,10 @@ def test_get_analytics_response_structure(self):
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"
+ kwargs["id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.posts_client, "get_analytics")
+ 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
@@ -1689,8 +1693,8 @@ def test_get_analytics_response_structure(self):
)
- def test_hide_reply_request_structure(self):
- """Test hide_reply 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()
@@ -1699,19 +1703,15 @@ def test_hide_reply_request_structure(self):
"data": None,
}
mock_response.raise_for_status.return_value = None
- mock_session.put.return_value = mock_response
+ mock_session.delete.return_value = mock_response
# Prepare test parameters
kwargs = {}
# Add required parameters
- kwargs["tweet_id"] = "test_value"
+ kwargs["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.posts_client, "hide_reply")
+ method = getattr(self.posts_client, "delete")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1730,7 +1730,7 @@ def test_hide_reply_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.put.return_value = mock_streaming_response
+ mock_session.delete.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -1739,14 +1739,14 @@ def test_hide_reply_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# Verify the request was made
- mock_session.put.assert_called_once()
+ mock_session.delete.assert_called_once()
# Verify request structure
- call_args = mock_session.put.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/tweets/{tweet_id}/hidden"
+ expected_path = "/2/tweets/{id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1762,12 +1762,12 @@ def test_hide_reply_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for hide_reply: {e}")
+ pytest.fail(f"Contract test failed for delete: {e}")
- def test_hide_reply_required_parameters(self):
- """Test that hide_reply handles parameters correctly."""
- method = getattr(self.posts_client, "hide_reply")
+ 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)
@@ -1775,14 +1775,14 @@ def test_hide_reply_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.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_hide_reply_response_structure(self):
- """Test hide_reply 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 = {
@@ -1792,17 +1792,13 @@ def test_hide_reply_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.delete.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
- kwargs["tweet_id"] = "test"
+ kwargs["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.posts_client, "hide_reply")
+ 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
@@ -1814,8 +1810,8 @@ def test_hide_reply_response_structure(self):
)
- def test_get_reposts_request_structure(self):
- """Test get_reposts 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()
@@ -1828,11 +1824,13 @@ def test_get_reposts_request_structure(self):
# Prepare test parameters
kwargs = {}
# Add required parameters
- kwargs["id"] = "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.posts_client, "get_reposts")
+ method = getattr(self.posts_client, "get_insights28hr")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1867,7 +1865,7 @@ def test_get_reposts_request_structure(self):
called_url = (
call_args[0][0] if call_args[0] else call_args[1].get("url", "")
)
- expected_path = "/2/tweets/{id}/retweets"
+ expected_path = "/2/insights/28hr"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1883,12 +1881,12 @@ def test_get_reposts_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_reposts: {e}")
+ pytest.fail(f"Contract test failed for get_insights28hr: {e}")
- def test_get_reposts_required_parameters(self):
- """Test that get_reposts handles parameters correctly."""
- method = getattr(self.posts_client, "get_reposts")
+ 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)
@@ -1902,8 +1900,8 @@ def test_get_reposts_required_parameters(self):
method()
- def test_get_reposts_response_structure(self):
- """Test get_reposts 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 = {
@@ -1916,10 +1914,12 @@ def test_get_reposts_response_structure(self):
mock_session.get.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
- kwargs["id"] = "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.posts_client, "get_reposts")
+ 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
diff --git a/xdk/python/tests/posts/test_pagination.py b/xdk/python/tests/posts/test_pagination.py
index 5e2d67a1..de0f61e2 100644
--- a/xdk/python/tests/posts/test_pagination.py
+++ b/xdk/python/tests/posts/test_pagination.py
@@ -169,20 +169,20 @@ def test_get_quoted_pagination_parameters(self):
), "Pagination token should be passed correctly"
- def test_search_all_cursor_creation(self):
- """Test that search_all can be used with Cursor."""
- method = getattr(self.posts_client, "search_all")
+ 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_query", max_results=10)
+ test_cursor = cursor(method, "test_value", 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")
+ pytest.fail(f"Method get_reposted_by should support pagination")
- def test_search_all_cursor_pages(self):
- """Test pagination with pages() for search_all."""
+ 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()
@@ -203,8 +203,8 @@ def test_search_all_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.posts_client, "search_all")
- test_cursor = cursor(method, "test_query", max_results=2)
+ method = getattr(self.posts_client, "get_reposted_by")
+ test_cursor = cursor(method, "test_value", 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
@@ -219,8 +219,8 @@ def test_search_all_cursor_pages(self):
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."""
+ 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()
@@ -239,8 +239,8 @@ def test_search_all_cursor_items(self):
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)
+ method = getattr(self.posts_client, "get_reposted_by")
+ test_cursor = cursor(method, "test_value", 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
@@ -250,17 +250,17 @@ def test_search_all_cursor_items(self):
), "Items should have 'id' field"
- def test_search_all_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for search_all."""
+ 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, "search_all")
+ method = getattr(self.posts_client, "get_reposted_by")
# Test with max_results parameter
- test_cursor = cursor(method, "test_query", max_results=5)
+ test_cursor = cursor(method, "test_value", 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
@@ -289,7 +289,7 @@ def test_search_all_pagination_parameters(self):
mock_response_with_token,
second_page_response,
]
- test_cursor = cursor(method, "test_query", max_results=1)
+ test_cursor = cursor(method, "test_value", max_results=1)
pages = list(test_cursor.pages(2))
# Should have made 2 requests
assert (
@@ -311,20 +311,20 @@ def test_search_all_pagination_parameters(self):
), "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")
+ 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_value", 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")
+ pytest.fail(f"Method get_reposts should support pagination")
- def test_get_reposted_by_cursor_pages(self):
- """Test pagination with pages() for get_reposted_by."""
+ 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()
@@ -345,7 +345,7 @@ def test_get_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.posts_client, "get_reposted_by")
+ method = getattr(self.posts_client, "get_reposts")
test_cursor = cursor(method, "test_value", 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)}"
@@ -361,8 +361,8 @@ def test_get_reposted_by_cursor_pages(self):
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."""
+ 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()
@@ -381,7 +381,7 @@ def test_get_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.posts_client, "get_reposted_by")
+ method = getattr(self.posts_client, "get_reposts")
test_cursor = cursor(method, "test_value", 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)}"
@@ -392,15 +392,15 @@ def test_get_reposted_by_cursor_items(self):
), "Items should have 'id' field"
- def test_get_reposted_by_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_reposted_by."""
+ 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_reposted_by")
+ method = getattr(self.posts_client, "get_reposts")
# Test with max_results parameter
test_cursor = cursor(method, "test_value", max_results=5)
list(test_cursor.pages(1)) # Trigger one request
@@ -453,20 +453,20 @@ def test_get_reposted_by_pagination_parameters(self):
), "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")
+ 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_query", max_results=10)
+ test_cursor = cursor(method, "test_value", 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")
+ pytest.fail(f"Method get_liking_users should support pagination")
- def test_search_recent_cursor_pages(self):
- """Test pagination with pages() for search_recent."""
+ 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()
@@ -487,8 +487,8 @@ def test_search_recent_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.posts_client, "search_recent")
- test_cursor = cursor(method, "test_query", max_results=2)
+ method = getattr(self.posts_client, "get_liking_users")
+ test_cursor = cursor(method, "test_value", 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
@@ -503,8 +503,8 @@ def test_search_recent_cursor_pages(self):
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."""
+ 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()
@@ -523,8 +523,8 @@ def test_search_recent_cursor_items(self):
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)
+ method = getattr(self.posts_client, "get_liking_users")
+ test_cursor = cursor(method, "test_value", 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
@@ -534,17 +534,17 @@ def test_search_recent_cursor_items(self):
), "Items should have 'id' field"
- def test_search_recent_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for search_recent."""
+ 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, "search_recent")
+ method = getattr(self.posts_client, "get_liking_users")
# Test with max_results parameter
- test_cursor = cursor(method, "test_query", max_results=5)
+ test_cursor = cursor(method, "test_value", 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
@@ -573,7 +573,7 @@ def test_search_recent_pagination_parameters(self):
mock_response_with_token,
second_page_response,
]
- test_cursor = cursor(method, "test_query", max_results=1)
+ test_cursor = cursor(method, "test_value", max_results=1)
pages = list(test_cursor.pages(2))
# Should have made 2 requests
assert (
@@ -595,20 +595,20 @@ def test_search_recent_pagination_parameters(self):
), "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")
+ 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_value", max_results=10)
+ 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 get_liking_users should support pagination")
+ pytest.fail(f"Method search_all should support pagination")
- def test_get_liking_users_cursor_pages(self):
- """Test pagination with pages() for get_liking_users."""
+ 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()
@@ -629,8 +629,8 @@ def test_get_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.posts_client, "get_liking_users")
- test_cursor = cursor(method, "test_value", max_results=2)
+ 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
@@ -645,8 +645,8 @@ def test_get_liking_users_cursor_pages(self):
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."""
+ 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()
@@ -665,8 +665,8 @@ def test_get_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.posts_client, "get_liking_users")
- test_cursor = cursor(method, "test_value", max_results=10)
+ 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
@@ -676,17 +676,17 @@ def test_get_liking_users_cursor_items(self):
), "Items should have 'id' field"
- def test_get_liking_users_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_liking_users."""
+ 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, "get_liking_users")
+ method = getattr(self.posts_client, "search_all")
# Test with max_results parameter
- test_cursor = cursor(method, "test_value", max_results=5)
+ 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
@@ -715,7 +715,7 @@ def test_get_liking_users_pagination_parameters(self):
mock_response_with_token,
second_page_response,
]
- test_cursor = cursor(method, "test_value", max_results=1)
+ test_cursor = cursor(method, "test_query", max_results=1)
pages = list(test_cursor.pages(2))
# Should have made 2 requests
assert (
@@ -737,20 +737,20 @@ def test_get_liking_users_pagination_parameters(self):
), "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")
+ 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_value", max_results=10)
+ 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 get_reposts should support pagination")
+ pytest.fail(f"Method search_recent should support pagination")
- def test_get_reposts_cursor_pages(self):
- """Test pagination with pages() for get_reposts."""
+ 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()
@@ -771,8 +771,8 @@ def test_get_reposts_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.posts_client, "get_reposts")
- test_cursor = cursor(method, "test_value", max_results=2)
+ 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
@@ -787,8 +787,8 @@ def test_get_reposts_cursor_pages(self):
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."""
+ 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()
@@ -807,8 +807,8 @@ def test_get_reposts_cursor_items(self):
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_value", max_results=10)
+ 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
@@ -818,17 +818,17 @@ def test_get_reposts_cursor_items(self):
), "Items should have 'id' field"
- def test_get_reposts_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_reposts."""
+ 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, "get_reposts")
+ method = getattr(self.posts_client, "search_recent")
# Test with max_results parameter
- test_cursor = cursor(method, "test_value", max_results=5)
+ 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
@@ -857,7 +857,7 @@ def test_get_reposts_pagination_parameters(self):
mock_response_with_token,
second_page_response,
]
- test_cursor = cursor(method, "test_value", max_results=1)
+ test_cursor = cursor(method, "test_query", max_results=1)
pages = list(test_cursor.pages(2))
# Should have made 2 requests
assert (
diff --git a/xdk/python/tests/posts/test_structure.py b/xdk/python/tests/posts/test_structure.py
index 6fc5f6e9..4cc55e8f 100644
--- a/xdk/python/tests/posts/test_structure.py
+++ b/xdk/python/tests/posts/test_structure.py
@@ -100,41 +100,35 @@ def test_get_quoted_pagination_params(self):
), f"Paginated method get_quoted should have pagination parameters"
- def test_get_counts_all_exists(self):
- """Test that get_counts_all 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(PostsClient, "get_counts_all", None)
- assert (
- method is not None
- ), f"Method get_counts_all does not exist on PostsClient"
+ 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_counts_all 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_counts_all 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 = [
- "query",
+ "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_counts_all"
+ ), f"Required parameter '{required_param}' missing from get_analytics"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "start_time",
- "end_time",
- "since_id",
- "until_id",
- "next_token",
- "pagination_token",
- "granularity",
- "search_count.fields",
+ "analytics.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -144,48 +138,41 @@ def test_get_counts_all_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_counts_all_return_annotation(self):
- """Test that get_counts_all has proper return type annotation."""
- method = getattr(PostsClient, "get_counts_all")
+ 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_counts_all should have return type annotation"
+ ), f"Method get_analytics should have return type annotation"
- def test_get_by_id_exists(self):
- """Test that get_by_id 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(PostsClient, "get_by_id", None)
- assert method is not None, f"Method get_by_id does not exist on PostsClient"
+ 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"get_by_id 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"get_by_id 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 get_by_id"
+ ), f"Required parameter '{required_param}' missing from hide_reply"
# Check optional parameters have defaults (excluding 'self')
- optional_params = [
- "tweet.fields",
- "expansions",
- "media.fields",
- "poll.fields",
- "user.fields",
- "place.fields",
- ]
+ optional_params = []
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -194,28 +181,32 @@ def test_get_by_id_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_by_id_return_annotation(self):
- """Test that get_by_id has proper return type annotation."""
- method = getattr(PostsClient, "get_by_id")
+ 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 get_by_id should have return type annotation"
+ ), f"Method hide_reply should have return type annotation"
- def test_delete_exists(self):
- """Test that delete 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(PostsClient, "delete", None)
- assert method is not None, f"Method delete does not exist on PostsClient"
+ method = getattr(PostsClient, "get_reposted_by", None)
+ assert (
+ method is not None
+ ), f"Method get_reposted_by does not exist on PostsClient"
# Check method is callable
- assert callable(method), f"delete 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"delete should have at least 'self' parameter"
+ assert (
+ len(params) >= 1
+ ), f"get_reposted_by should have at least 'self' parameter"
assert (
params[0] == "self"
), f"First parameter should be 'self', got '{params[0]}'"
@@ -226,9 +217,15 @@ def test_delete_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from delete"
+ ), f"Required parameter '{required_param}' missing from get_reposted_by"
# Check optional parameters have defaults (excluding 'self')
- optional_params = []
+ optional_params = [
+ "max_results",
+ "pagination_token",
+ "user.fields",
+ "expansions",
+ "tweet.fields",
+ ]
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -237,48 +234,68 @@ def test_delete_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_delete_return_annotation(self):
- """Test that delete has proper return type annotation."""
- method = getattr(PostsClient, "delete")
+ 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 delete should have return type annotation"
+ ), f"Method get_reposted_by should have return type annotation"
- def test_get_insights28hr_exists(self):
- """Test that get_insights28hr method exists with correct signature."""
- # Check method exists
- method = getattr(PostsClient, "get_insights28hr", None)
+ 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
+ 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_insights28hr does not exist on PostsClient"
+ has_pagination_param
+ ), f"Paginated method get_reposted_by should have pagination parameters"
+
+
+ def test_get_reposts_exists(self):
+ """Test that get_reposts method exists with correct signature."""
+ # Check method exists
+ 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"get_insights28hr 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"get_insights28hr 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]}'"
# Check required parameters exist (excluding 'self')
required_params = [
- "tweet_ids",
- "granularity",
- "requested_metrics",
+ "id",
]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_insights28hr"
+ ), f"Required parameter '{required_param}' missing from get_reposts"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "engagement.fields",
+ "max_results",
+ "pagination_token",
+ "tweet.fields",
+ "expansions",
+ "media.fields",
+ "poll.fields",
+ "user.fields",
+ "place.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -288,53 +305,66 @@ def test_get_insights28hr_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_insights28hr_return_annotation(self):
- """Test that get_insights28hr has proper return type annotation."""
- method = getattr(PostsClient, "get_insights28hr")
+ 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 get_insights28hr should have return type annotation"
+ ), f"Method get_reposts should have return type annotation"
- def test_get_counts_recent_exists(self):
- """Test that get_counts_recent method exists with correct signature."""
- # Check method exists
- method = getattr(PostsClient, "get_counts_recent", None)
+ 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 (
- method is not None
- ), f"Method get_counts_recent does not exist on PostsClient"
+ has_pagination_param
+ ), f"Paginated method get_reposts should have pagination parameters"
+
+
+ def test_get_by_ids_exists(self):
+ """Test that get_by_ids method exists with correct signature."""
+ # Check method exists
+ 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_counts_recent 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_counts_recent 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 = [
- "query",
+ "ids",
]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_counts_recent"
+ ), f"Required parameter '{required_param}' missing from get_by_ids"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "start_time",
- "end_time",
- "since_id",
- "until_id",
- "next_token",
- "pagination_token",
- "granularity",
- "search_count.fields",
+ "tweet.fields",
+ "expansions",
+ "media.fields",
+ "poll.fields",
+ "user.fields",
+ "place.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -344,56 +374,39 @@ def test_get_counts_recent_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_counts_recent_return_annotation(self):
- """Test that get_counts_recent has proper return type annotation."""
- method = getattr(PostsClient, "get_counts_recent")
+ 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_counts_recent should have return type annotation"
+ ), f"Method get_by_ids should have return type annotation"
- def test_search_all_exists(self):
- """Test that search_all method exists with correct signature."""
+ def test_create_exists(self):
+ """Test that create method exists with correct signature."""
# Check method exists
- method = getattr(PostsClient, "search_all", None)
- assert method is not None, f"Method search_all does not exist on PostsClient"
+ 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"search_all 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"search_all 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 = [
- "query",
- ]
+ required_params = []
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from search_all"
+ ), f"Required parameter '{required_param}' missing from create"
# 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",
- "tweet.fields",
- "expansions",
- "media.fields",
- "poll.fields",
- "user.fields",
- "place.fields",
- ]
+ optional_params = []
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -402,51 +415,32 @@ def test_search_all_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_search_all_return_annotation(self):
- """Test that search_all has proper return type annotation."""
- method = getattr(PostsClient, "search_all")
+ 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 search_all should have return type annotation"
-
-
- 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
- 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_all should have pagination parameters"
+ ), f"Method create should have return type annotation"
- def test_get_reposted_by_exists(self):
- """Test that get_reposted_by 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(PostsClient, "get_reposted_by", None)
+ method = getattr(PostsClient, "get_liking_users", None)
assert (
method is not None
- ), f"Method get_reposted_by does not exist on PostsClient"
+ ), f"Method get_liking_users does not exist on PostsClient"
# Check method is callable
- assert callable(method), f"get_reposted_by 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"get_reposted_by should have at least 'self' parameter"
+ ), f"get_liking_users should have at least 'self' parameter"
assert (
params[0] == "self"
), f"First parameter should be 'self', got '{params[0]}'"
@@ -457,7 +451,7 @@ def test_get_reposted_by_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_reposted_by"
+ ), f"Required parameter '{required_param}' missing from get_liking_users"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
"max_results",
@@ -474,19 +468,19 @@ def test_get_reposted_by_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_reposted_by_return_annotation(self):
- """Test that get_reposted_by has proper return type annotation."""
- method = getattr(PostsClient, "get_reposted_by")
+ 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 get_reposted_by should have return type annotation"
+ ), f"Method get_liking_users should have return type annotation"
- def test_get_reposted_by_pagination_params(self):
- """Test that get_reposted_by has pagination parameters."""
- method = getattr(PostsClient, "get_reposted_by")
+ 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 pagination-related parameters
@@ -500,21 +494,25 @@ def test_get_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_reposted_by should have pagination parameters"
+ ), f"Paginated method get_liking_users should have pagination parameters"
- def test_search_recent_exists(self):
- """Test that search_recent 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(PostsClient, "search_recent", None)
- assert method is not None, f"Method search_recent does not exist on PostsClient"
+ method = getattr(PostsClient, "get_counts_recent", None)
+ assert (
+ method is not None
+ ), f"Method get_counts_recent does not exist on PostsClient"
# Check method is callable
- assert callable(method), f"search_recent 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"search_recent should have at least 'self' parameter"
+ assert (
+ len(params) >= 1
+ ), f"get_counts_recent should have at least 'self' parameter"
assert (
params[0] == "self"
), f"First parameter should be 'self', got '{params[0]}'"
@@ -525,23 +523,17 @@ def test_search_recent_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from search_recent"
+ ), f"Required parameter '{required_param}' missing from get_counts_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",
- "tweet.fields",
- "expansions",
- "media.fields",
- "poll.fields",
- "user.fields",
- "place.fields",
+ "granularity",
+ "search_count.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -551,69 +543,51 @@ def test_search_recent_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_search_recent_return_annotation(self):
- """Test that search_recent has proper return type annotation."""
- method = getattr(PostsClient, "search_recent")
+ 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 search_recent should have return type annotation"
-
-
- 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
- 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_recent should have pagination parameters"
+ ), f"Method get_counts_recent should have return type annotation"
- def test_get_insights_historical_exists(self):
- """Test that get_insights_historical 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(PostsClient, "get_insights_historical", None)
+ method = getattr(PostsClient, "get_counts_all", None)
assert (
method is not None
- ), f"Method get_insights_historical does not exist on PostsClient"
+ ), f"Method get_counts_all does not exist on PostsClient"
# Check method is callable
- assert callable(method), f"get_insights_historical 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_insights_historical 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 = [
- "tweet_ids",
- "end_time",
- "start_time",
- "granularity",
- "requested_metrics",
+ "query",
]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_insights_historical"
+ ), f"Required parameter '{required_param}' missing from get_counts_all"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "engagement.fields",
+ "start_time",
+ "end_time",
+ "since_id",
+ "until_id",
+ "next_token",
+ "pagination_token",
+ "granularity",
+ "search_count.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -623,89 +597,56 @@ def test_get_insights_historical_exists(self):
), 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(PostsClient, "get_insights_historical")
+ 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_insights_historical should have return type annotation"
+ ), f"Method get_counts_all should have return type annotation"
- def test_get_by_ids_exists(self):
- """Test that get_by_ids 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(PostsClient, "get_by_ids", None)
- assert method is not None, f"Method get_by_ids does not exist on PostsClient"
+ 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_by_ids 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_by_ids 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 = [
- "ids",
+ "query",
]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_by_ids"
+ ), 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",
"tweet.fields",
"expansions",
"media.fields",
"poll.fields",
- "user.fields",
- "place.fields",
- ]
- 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(PostsClient, "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_create_exists(self):
- """Test that create method exists with correct signature."""
- # Check method exists
- 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"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 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"
- # Check optional parameters have defaults (excluding 'self')
- optional_params = []
+ "user.fields",
+ "place.fields",
+ ]
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -714,50 +655,74 @@ def test_create_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_create_return_annotation(self):
- """Test that create has proper return type annotation."""
- method = getattr(PostsClient, "create")
+ 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 create should have return type annotation"
+ ), f"Method search_all should have return type annotation"
- def test_get_liking_users_exists(self):
- """Test that get_liking_users method exists with correct signature."""
- # Check method exists
- method = getattr(PostsClient, "get_liking_users", None)
+ 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
+ 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_liking_users does not exist on PostsClient"
+ has_pagination_param
+ ), f"Paginated method search_all should have pagination parameters"
+
+
+ def test_search_recent_exists(self):
+ """Test that search_recent method exists with correct signature."""
+ # Check method exists
+ 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_liking_users 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_liking_users 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_liking_users"
+ ), 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",
- "user.fields",
- "expansions",
+ "sort_order",
"tweet.fields",
+ "expansions",
+ "media.fields",
+ "poll.fields",
+ "user.fields",
+ "place.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -767,19 +732,19 @@ def test_get_liking_users_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_liking_users_return_annotation(self):
- """Test that get_liking_users has proper return type annotation."""
- method = getattr(PostsClient, "get_liking_users")
+ 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_liking_users should have return type annotation"
+ ), f"Method search_recent should have return type annotation"
- def test_get_liking_users_pagination_params(self):
- """Test that get_liking_users has pagination parameters."""
- method = getattr(PostsClient, "get_liking_users")
+ 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
@@ -793,38 +758,43 @@ def test_get_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_liking_users should have pagination parameters"
+ ), f"Paginated method search_recent should have pagination parameters"
- def test_get_analytics_exists(self):
- """Test that get_analytics 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(PostsClient, "get_analytics", None)
- assert method is not None, f"Method get_analytics does not exist on PostsClient"
+ method = getattr(PostsClient, "get_insights_historical", None)
+ assert (
+ method is not None
+ ), f"Method get_insights_historical does not exist on PostsClient"
# Check method is callable
- assert callable(method), f"get_analytics 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_analytics should have at least 'self' 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 = [
- "ids",
+ "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_analytics"
+ ), f"Required parameter '{required_param}' missing from get_insights_historical"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "analytics.fields",
+ "engagement.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -834,41 +804,48 @@ def test_get_analytics_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_analytics_return_annotation(self):
- """Test that get_analytics has proper return type annotation."""
- method = getattr(PostsClient, "get_analytics")
+ 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_analytics should have return type annotation"
+ ), f"Method get_insights_historical should have return type annotation"
- def test_hide_reply_exists(self):
- """Test that hide_reply 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(PostsClient, "hide_reply", None)
- assert method is not None, f"Method hide_reply does not exist on PostsClient"
+ 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"hide_reply 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"hide_reply 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 = [
- "tweet_id",
+ "id",
]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from hide_reply"
+ ), f"Required parameter '{required_param}' missing from get_by_id"
# Check optional parameters have defaults (excluding 'self')
- optional_params = []
+ optional_params = [
+ "tweet.fields",
+ "expansions",
+ "media.fields",
+ "poll.fields",
+ "user.fields",
+ "place.fields",
+ ]
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -877,28 +854,28 @@ def test_hide_reply_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_hide_reply_return_annotation(self):
- """Test that hide_reply has proper return type annotation."""
- method = getattr(PostsClient, "hide_reply")
+ 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 hide_reply should have return type annotation"
+ ), f"Method get_by_id should have return type annotation"
- def test_get_reposts_exists(self):
- """Test that get_reposts method exists with correct signature."""
+ def test_delete_exists(self):
+ """Test that delete method exists with correct signature."""
# Check method exists
- method = getattr(PostsClient, "get_reposts", None)
- assert method is not None, f"Method get_reposts does not exist on PostsClient"
+ 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"get_reposts 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_reposts 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]}'"
@@ -909,18 +886,9 @@ def test_get_reposts_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_reposts"
+ ), f"Required parameter '{required_param}' missing from delete"
# Check optional parameters have defaults (excluding 'self')
- optional_params = [
- "max_results",
- "pagination_token",
- "tweet.fields",
- "expansions",
- "media.fields",
- "poll.fields",
- "user.fields",
- "place.fields",
- ]
+ optional_params = []
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -929,54 +897,86 @@ def test_get_reposts_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_reposts_return_annotation(self):
- """Test that get_reposts has proper return type annotation."""
- method = getattr(PostsClient, "get_reposts")
+ 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 get_reposts should have return type annotation"
+ ), f"Method delete should have return type annotation"
- def test_get_reposts_pagination_params(self):
- """Test that get_reposts has pagination parameters."""
- method = getattr(PostsClient, "get_reposts")
+ def test_get_insights28hr_exists(self):
+ """Test that get_insights28hr method exists with correct signature."""
+ # Check method exists
+ 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"get_insights28hr is not callable"
+ # Check method signature
sig = inspect.signature(method)
params = list(sig.parameters.keys())
- # Should have pagination-related parameters
- pagination_params = [
- "pagination_token",
- "max_results",
- "next_token",
- "cursor",
- "limit",
+ # Should have 'self' as first 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 = [
+ "tweet_ids",
+ "granularity",
+ "requested_metrics",
]
- has_pagination_param = any(param in params for param in pagination_params)
+ for required_param in required_params:
+ assert (
+ required_param in params
+ ), f"Required parameter '{required_param}' missing from get_insights28hr"
+ # Check optional parameters have defaults (excluding 'self')
+ optional_params = [
+ "engagement.fields",
+ ]
+ 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_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 (
- has_pagination_param
- ), f"Paginated method get_reposts should have pagination parameters"
+ sig.return_annotation is not inspect.Signature.empty
+ ), f"Method get_insights28hr should have return type annotation"
def test_all_expected_methods_exist(self):
"""Test that all expected methods exist on the client."""
expected_methods = [
"get_quoted",
- "get_counts_all",
- "get_by_id",
- "delete",
- "get_insights28hr",
- "get_counts_recent",
- "search_all",
+ "get_analytics",
+ "hide_reply",
"get_reposted_by",
- "search_recent",
- "get_insights_historical",
+ "get_reposts",
"get_by_ids",
"create",
"get_liking_users",
- "get_analytics",
- "hide_reply",
- "get_reposts",
+ "get_counts_recent",
+ "get_counts_all",
+ "search_all",
+ "search_recent",
+ "get_insights_historical",
+ "get_by_id",
+ "delete",
+ "get_insights28hr",
]
for expected_method in expected_methods:
assert hasattr(
diff --git a/xdk/python/tests/spaces/test_contracts.py b/xdk/python/tests/spaces/test_contracts.py
index fbd2780f..14be91d9 100644
--- a/xdk/python/tests/spaces/test_contracts.py
+++ b/xdk/python/tests/spaces/test_contracts.py
@@ -27,8 +27,8 @@ def setup_class(self):
self.spaces_client = getattr(self.client, "spaces")
- def test_get_by_creator_ids_request_structure(self):
- """Test get_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()
@@ -41,11 +41,11 @@ def test_get_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_by_creator_ids")
+ method = getattr(self.spaces_client, "get_posts")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -80,7 +80,7 @@ def test_get_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(
@@ -96,12 +96,12 @@ def test_get_by_creator_ids_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_by_creator_ids: {e}")
+ pytest.fail(f"Contract test failed for get_posts: {e}")
- 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")
+ 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)
@@ -115,8 +115,8 @@ def test_get_by_creator_ids_required_parameters(self):
method()
- def test_get_by_creator_ids_response_structure(self):
- """Test get_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 = {
@@ -129,10 +129,10 @@ def test_get_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_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
@@ -144,8 +144,8 @@ def test_get_by_creator_ids_response_structure(self):
)
- def test_get_by_id_request_structure(self):
- """Test get_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()
@@ -158,11 +158,11 @@ def test_get_by_id_request_structure(self):
# Prepare test parameters
kwargs = {}
# Add required parameters
- kwargs["id"] = "test_id"
+ kwargs["query"] = "test_query"
# Add request body if required
# Call the method
try:
- method = getattr(self.spaces_client, "get_by_id")
+ method = getattr(self.spaces_client, "search")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -197,7 +197,7 @@ def test_get_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/search"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -213,12 +213,12 @@ def test_get_by_id_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_by_id: {e}")
+ pytest.fail(f"Contract test failed for search: {e}")
- def test_get_by_id_required_parameters(self):
- """Test that get_by_id handles parameters correctly."""
- method = getattr(self.spaces_client, "get_by_id")
+ 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)
@@ -232,8 +232,8 @@ def test_get_by_id_required_parameters(self):
method()
- def test_get_by_id_response_structure(self):
- """Test get_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 = {
@@ -246,10 +246,10 @@ def test_get_by_id_response_structure(self):
mock_session.get.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
- kwargs["id"] = "test_value"
+ kwargs["query"] = "test_value"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.spaces_client, "get_by_id")
+ 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
@@ -261,8 +261,8 @@ def test_get_by_id_response_structure(self):
)
- def test_get_by_ids_request_structure(self):
- """Test get_by_ids 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()
@@ -275,11 +275,11 @@ def test_get_by_ids_request_structure(self):
# Prepare test parameters
kwargs = {}
# Add required parameters
- kwargs["ids"] = ["test_item"]
+ kwargs["id"] = "test_id"
# Add request body if required
# Call the method
try:
- method = getattr(self.spaces_client, "get_by_ids")
+ method = getattr(self.spaces_client, "get_buyers")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -314,7 +314,7 @@ def test_get_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/{id}/buyers"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -330,12 +330,12 @@ def test_get_by_ids_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_by_ids: {e}")
+ pytest.fail(f"Contract test failed for get_buyers: {e}")
- def test_get_by_ids_required_parameters(self):
- """Test that get_by_ids handles parameters correctly."""
- method = getattr(self.spaces_client, "get_by_ids")
+ 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)
@@ -349,8 +349,8 @@ def test_get_by_ids_required_parameters(self):
method()
- def test_get_by_ids_response_structure(self):
- """Test get_by_ids 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 = {
@@ -363,10 +363,10 @@ def test_get_by_ids_response_structure(self):
mock_session.get.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
- kwargs["ids"] = ["test"]
+ kwargs["id"] = "test_value"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.spaces_client, "get_by_ids")
+ 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
@@ -378,8 +378,8 @@ def test_get_by_ids_response_structure(self):
)
- def test_get_posts_request_structure(self):
- """Test get_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()
@@ -396,7 +396,7 @@ def test_get_posts_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.spaces_client, "get_posts")
+ method = getattr(self.spaces_client, "get_by_id")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -431,7 +431,7 @@ def test_get_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(
@@ -447,12 +447,12 @@ def test_get_posts_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_posts: {e}")
+ pytest.fail(f"Contract test failed for get_by_id: {e}")
- def test_get_posts_required_parameters(self):
- """Test that get_posts handles parameters correctly."""
- method = getattr(self.spaces_client, "get_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)
@@ -466,8 +466,8 @@ def test_get_posts_required_parameters(self):
method()
- def test_get_posts_response_structure(self):
- """Test get_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 = {
@@ -483,7 +483,7 @@ def test_get_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_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
@@ -495,8 +495,8 @@ def test_get_posts_response_structure(self):
)
- def test_get_buyers_request_structure(self):
- """Test get_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()
@@ -509,11 +509,11 @@ def test_get_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_buyers")
+ method = getattr(self.spaces_client, "get_by_ids")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -548,7 +548,7 @@ def test_get_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(
@@ -564,12 +564,12 @@ def test_get_buyers_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_buyers: {e}")
+ pytest.fail(f"Contract test failed for get_by_ids: {e}")
- def test_get_buyers_required_parameters(self):
- """Test that get_buyers handles parameters correctly."""
- method = getattr(self.spaces_client, "get_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)
@@ -583,8 +583,8 @@ def test_get_buyers_required_parameters(self):
method()
- def test_get_buyers_response_structure(self):
- """Test get_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 = {
@@ -597,10 +597,10 @@ def test_get_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_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
@@ -612,8 +612,8 @@ def test_get_buyers_response_structure(self):
)
- def test_search_request_structure(self):
- """Test search 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()
@@ -626,11 +626,11 @@ def test_search_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")
+ method = getattr(self.spaces_client, "get_by_creator_ids")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -665,7 +665,7 @@ def test_search_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(
@@ -681,12 +681,12 @@ def test_search_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for search: {e}")
+ pytest.fail(f"Contract test failed for get_by_creator_ids: {e}")
- def test_search_required_parameters(self):
- """Test that search handles parameters correctly."""
- method = getattr(self.spaces_client, "search")
+ 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)
@@ -700,8 +700,8 @@ def test_search_required_parameters(self):
method()
- def test_search_response_structure(self):
- """Test search 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 = {
@@ -714,10 +714,10 @@ def test_search_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")
+ 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_structure.py b/xdk/python/tests/spaces/test_structure.py
index 680d91fd..c2d832fb 100644
--- a/xdk/python/tests/spaces/test_structure.py
+++ b/xdk/python/tests/spaces/test_structure.py
@@ -28,39 +28,38 @@ def setup_class(self):
self.spaces_client = getattr(self.client, "spaces")
- def test_get_by_creator_ids_exists(self):
- """Test that get_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_by_creator_ids", None)
- assert (
- method is not None
- ), f"Method get_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_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_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_by_creator_ids"
+ ), f"Required parameter '{required_param}' missing from get_posts"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "space.fields",
+ "max_results",
+ "tweet.fields",
"expansions",
+ "media.fields",
+ "poll.fields",
"user.fields",
- "topic.fields",
+ "place.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -70,41 +69,43 @@ def test_get_by_creator_ids_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- 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")
+ 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_by_creator_ids should have return type annotation"
+ ), f"Method get_posts should have return type annotation"
- def test_get_by_id_exists(self):
- """Test that get_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(SpacesClient, "get_by_id", None)
- assert method is not None, f"Method get_by_id 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_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_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_by_id"
+ ), f"Required parameter '{required_param}' missing from search"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
+ "state",
+ "max_results",
"space.fields",
"expansions",
"user.fields",
@@ -118,45 +119,46 @@ def test_get_by_id_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_by_id_return_annotation(self):
- """Test that get_by_id has proper return type annotation."""
- method = getattr(SpacesClient, "get_by_id")
+ 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_by_id should have return type annotation"
+ ), f"Method search should have return type annotation"
- def test_get_by_ids_exists(self):
- """Test that get_by_ids 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_by_ids", None)
- assert method is not None, f"Method get_by_ids 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_by_ids 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_by_ids 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]}'"
# 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_by_ids"
+ ), f"Required parameter '{required_param}' missing from get_buyers"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "space.fields",
- "expansions",
+ "pagination_token",
+ "max_results",
"user.fields",
- "topic.fields",
+ "expansions",
+ "tweet.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -166,28 +168,47 @@ def test_get_by_ids_exists(self):
), 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(SpacesClient, "get_by_ids")
+ 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_by_ids should have return type annotation"
+ ), f"Method get_buyers should have return type annotation"
- def test_get_posts_exists(self):
- """Test that get_posts method exists with correct signature."""
+ 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 (
+ 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_posts", None)
- assert method is not None, f"Method get_posts does not exist on SpacesClient"
+ 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_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_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]}'"
@@ -198,16 +219,13 @@ def test_get_posts_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_posts"
+ ), f"Required parameter '{required_param}' missing from get_by_id"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "max_results",
- "tweet.fields",
+ "space.fields",
"expansions",
- "media.fields",
- "poll.fields",
"user.fields",
- "place.fields",
+ "topic.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -217,46 +235,45 @@ def test_get_posts_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_posts_return_annotation(self):
- """Test that get_posts has proper return type annotation."""
- method = getattr(SpacesClient, "get_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_posts should have return type annotation"
+ ), f"Method get_by_id should have return type annotation"
- def test_get_buyers_exists(self):
- """Test that get_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_buyers", None)
- assert method is not None, f"Method get_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_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_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_buyers"
+ ), f"Required parameter '{required_param}' missing from get_by_ids"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "pagination_token",
- "max_results",
- "user.fields",
+ "space.fields",
"expansions",
- "tweet.fields",
+ "user.fields",
+ "topic.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -266,62 +283,45 @@ def test_get_buyers_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_buyers_return_annotation(self):
- """Test that get_buyers has proper return type annotation."""
- method = getattr(SpacesClient, "get_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_buyers should have return type annotation"
-
-
- 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 (
- has_pagination_param
- ), f"Paginated method get_buyers should have pagination parameters"
+ ), f"Method get_by_ids should have return type annotation"
- def test_search_exists(self):
- """Test that search 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", None)
- assert method is not None, f"Method search does not exist on SpacesClient"
+ method = getattr(SpacesClient, "get_by_creator_ids", None)
+ assert (
+ method is not None
+ ), f"Method get_by_creator_ids does not exist on SpacesClient"
# Check method is callable
- assert callable(method), f"search 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 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"
+ ), f"Required parameter '{required_param}' missing from get_by_creator_ids"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "state",
- "max_results",
"space.fields",
"expansions",
"user.fields",
@@ -335,25 +335,25 @@ def test_search_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_search_return_annotation(self):
- """Test that search has proper return type annotation."""
- method = getattr(SpacesClient, "search")
+ 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 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_by_creator_ids",
- "get_by_id",
- "get_by_ids",
"get_posts",
- "get_buyers",
"search",
+ "get_buyers",
+ "get_by_id",
+ "get_by_ids",
+ "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 a5f7038e..78ada05e 100644
--- a/xdk/python/tests/stream/test_contracts.py
+++ b/xdk/python/tests/stream/test_contracts.py
@@ -27,8 +27,8 @@ def setup_class(self):
self.stream_client = getattr(self.client, "stream")
- def test_posts_sample_request_structure(self):
- """Test posts_sample 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()
@@ -41,10 +41,11 @@ def test_posts_sample_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, "posts_sample")
+ method = getattr(self.stream_client, "likes_firehose")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -79,7 +80,7 @@ def test_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/likes/firehose/stream"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -95,27 +96,27 @@ def test_posts_sample_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for posts_sample: {e}")
+ pytest.fail(f"Contract test failed for likes_firehose: {e}")
- 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
+ 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)
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_posts_sample_response_structure(self):
- """Test posts_sample 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 = {
@@ -128,9 +129,10 @@ def test_posts_sample_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, "posts_sample")
+ 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
@@ -142,8 +144,8 @@ def test_posts_sample_response_structure(self):
)
- def test_get_rule_counts_request_structure(self):
- """Test get_rule_counts 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()
@@ -156,10 +158,11 @@ def test_get_rule_counts_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_rule_counts")
+ method = getattr(self.stream_client, "posts_firehose_pt")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -194,7 +197,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/tweets/firehose/stream/lang/pt"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -210,27 +213,27 @@ def test_get_rule_counts_request_structure(self):
# For regular operations, verify we got a result
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 posts_firehose_pt: {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
+ 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)
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_rule_counts_response_structure(self):
- """Test get_rule_counts 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 = {
@@ -243,9 +246,10 @@ def test_get_rule_counts_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_rule_counts")
+ 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
@@ -257,8 +261,8 @@ def test_get_rule_counts_response_structure(self):
)
- def test_posts_firehose_request_structure(self):
- """Test posts_firehose 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()
@@ -275,7 +279,7 @@ def test_posts_firehose_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.stream_client, "posts_firehose")
+ method = getattr(self.stream_client, "posts_firehose_ja")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -310,7 +314,7 @@ def test_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/tweets/firehose/stream/lang/ja"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -326,12 +330,12 @@ def test_posts_firehose_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for posts_firehose: {e}")
+ pytest.fail(f"Contract test failed for posts_firehose_ja: {e}")
- def test_posts_firehose_required_parameters(self):
- """Test that posts_firehose handles parameters correctly."""
- method = getattr(self.stream_client, "posts_firehose")
+ 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)
@@ -345,8 +349,8 @@ def test_posts_firehose_required_parameters(self):
method()
- def test_posts_firehose_response_structure(self):
- """Test posts_firehose 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 = {
@@ -362,7 +366,7 @@ def test_posts_firehose_response_structure(self):
kwargs["partition"] = 1
# Add request body if required
# Call method and verify response structure
- method = getattr(self.stream_client, "posts_firehose")
+ 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
@@ -374,8 +378,8 @@ def test_posts_firehose_response_structure(self):
)
- def test_posts_firehose_pt_request_structure(self):
- """Test posts_firehose_pt 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()
@@ -388,11 +392,10 @@ def test_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, "posts_firehose_pt")
+ method = getattr(self.stream_client, "labels_compliance")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -427,7 +430,7 @@ def test_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/label/stream"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -443,27 +446,27 @@ def test_posts_firehose_pt_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for posts_firehose_pt: {e}")
+ pytest.fail(f"Contract test failed for labels_compliance: {e}")
- 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
+ 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_posts_firehose_pt_response_structure(self):
- """Test posts_firehose_pt 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 = {
@@ -476,10 +479,9 @@ def test_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, "posts_firehose_pt")
+ 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
@@ -491,8 +493,8 @@ def test_posts_firehose_pt_response_structure(self):
)
- def test_users_compliance_request_structure(self):
- """Test users_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()
@@ -509,7 +511,7 @@ def test_users_compliance_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.stream_client, "users_compliance")
+ method = getattr(self.stream_client, "posts_firehose_ko")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -544,7 +546,7 @@ def test_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/firehose/stream/lang/ko"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -560,12 +562,12 @@ def test_users_compliance_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for users_compliance: {e}")
+ pytest.fail(f"Contract test failed for posts_firehose_ko: {e}")
- def test_users_compliance_required_parameters(self):
- """Test that users_compliance handles parameters correctly."""
- method = getattr(self.stream_client, "users_compliance")
+ 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)
@@ -579,8 +581,8 @@ def test_users_compliance_required_parameters(self):
method()
- def test_users_compliance_response_structure(self):
- """Test users_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 = {
@@ -596,7 +598,7 @@ def test_users_compliance_response_structure(self):
kwargs["partition"] = 1
# Add request body if required
# Call method and verify response structure
- method = getattr(self.stream_client, "users_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
@@ -608,8 +610,8 @@ def test_users_compliance_response_structure(self):
)
- def test_posts_sample10_request_structure(self):
- """Test posts_sample10 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()
@@ -622,11 +624,10 @@ def test_posts_sample10_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, "posts_sample10")
+ method = getattr(self.stream_client, "posts")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -661,7 +662,7 @@ def test_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/search/stream"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -677,27 +678,27 @@ def test_posts_sample10_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for posts_sample10: {e}")
+ pytest.fail(f"Contract test failed for posts: {e}")
- 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
+ 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 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_posts_sample10_response_structure(self):
- """Test posts_sample10 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 = {
@@ -710,10 +711,9 @@ def test_posts_sample10_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, "posts_sample10")
+ 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
@@ -840,8 +840,8 @@ def test_likes_compliance_response_structure(self):
)
- def test_labels_compliance_request_structure(self):
- """Test labels_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()
@@ -857,7 +857,7 @@ def test_labels_compliance_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.stream_client, "labels_compliance")
+ method = getattr(self.stream_client, "get_rules")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -892,7 +892,7 @@ def test_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/search/stream/rules"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -908,12 +908,12 @@ def test_labels_compliance_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for labels_compliance: {e}")
+ pytest.fail(f"Contract test failed for get_rules: {e}")
- def test_labels_compliance_required_parameters(self):
- """Test that labels_compliance handles parameters correctly."""
- method = getattr(self.stream_client, "labels_compliance")
+ 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()
@@ -927,8 +927,8 @@ def test_labels_compliance_required_parameters(self):
pytest.fail(f"Method with no required params should be callable: {e}")
- def test_labels_compliance_response_structure(self):
- """Test labels_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 = {
@@ -943,7 +943,7 @@ def test_labels_compliance_response_structure(self):
kwargs = {}
# Add request body if required
# Call method and verify response structure
- method = getattr(self.stream_client, "labels_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
@@ -955,8 +955,8 @@ def test_labels_compliance_response_structure(self):
)
- def test_posts_firehose_en_request_structure(self):
- """Test posts_firehose_en 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()
@@ -965,15 +965,18 @@ def test_posts_firehose_en_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, "posts_firehose_en")
+ method = getattr(self.stream_client, "update_rules")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -992,7 +995,7 @@ def test_posts_firehose_en_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -1001,14 +1004,14 @@ def test_posts_firehose_en_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/en"
+ expected_path = "/2/tweets/search/stream/rules"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1024,12 +1027,12 @@ def test_posts_firehose_en_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for posts_firehose_en: {e}")
+ pytest.fail(f"Contract test failed for update_rules: {e}")
- def test_posts_firehose_en_required_parameters(self):
- """Test that posts_firehose_en handles parameters correctly."""
- method = getattr(self.stream_client, "posts_firehose_en")
+ 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)
@@ -1037,14 +1040,14 @@ def test_posts_firehose_en_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_posts_firehose_en_response_structure(self):
- """Test posts_firehose_en 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 = {
@@ -1054,13 +1057,16 @@ def test_posts_firehose_en_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, "posts_firehose_en")
+ 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
@@ -1072,8 +1078,8 @@ def test_posts_firehose_en_response_structure(self):
)
- def test_posts_request_structure(self):
- """Test posts 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()
@@ -1089,7 +1095,7 @@ def test_posts_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.stream_client, "posts")
+ method = getattr(self.stream_client, "get_rule_counts")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1124,7 +1130,7 @@ def test_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/search/stream/rules/counts"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1140,12 +1146,12 @@ def test_posts_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for posts: {e}")
+ pytest.fail(f"Contract test failed for get_rule_counts: {e}")
- def test_posts_required_parameters(self):
- """Test that posts handles parameters correctly."""
- method = getattr(self.stream_client, "posts")
+ 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()
@@ -1159,8 +1165,8 @@ def test_posts_required_parameters(self):
pytest.fail(f"Method with no required params should be callable: {e}")
- def test_posts_response_structure(self):
- """Test posts 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 = {
@@ -1175,7 +1181,7 @@ def test_posts_response_structure(self):
kwargs = {}
# Add request body if required
# Call method and verify response structure
- method = getattr(self.stream_client, "posts")
+ 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
@@ -1187,8 +1193,8 @@ def test_posts_response_structure(self):
)
- def test_posts_firehose_ko_request_structure(self):
- """Test posts_firehose_ko 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()
@@ -1205,7 +1211,7 @@ def test_posts_firehose_ko_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.stream_client, "posts_firehose_ko")
+ method = getattr(self.stream_client, "likes_sample10")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1240,7 +1246,7 @@ def test_posts_firehose_ko_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/ko"
+ expected_path = "/2/likes/sample10/stream"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1256,12 +1262,12 @@ def test_posts_firehose_ko_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for posts_firehose_ko: {e}")
+ pytest.fail(f"Contract test failed for likes_sample10: {e}")
- def test_posts_firehose_ko_required_parameters(self):
- """Test that posts_firehose_ko handles parameters correctly."""
- method = getattr(self.stream_client, "posts_firehose_ko")
+ 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)
@@ -1275,8 +1281,8 @@ def test_posts_firehose_ko_required_parameters(self):
method()
- def test_posts_firehose_ko_response_structure(self):
- """Test posts_firehose_ko 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 = {
@@ -1292,7 +1298,7 @@ def test_posts_firehose_ko_response_structure(self):
kwargs["partition"] = 1
# Add request body if required
# Call method and verify response structure
- method = getattr(self.stream_client, "posts_firehose_ko")
+ 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
@@ -1304,8 +1310,8 @@ def test_posts_firehose_ko_response_structure(self):
)
- def test_likes_sample10_request_structure(self):
- """Test likes_sample10 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()
@@ -1322,7 +1328,7 @@ def test_likes_sample10_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.stream_client, "likes_sample10")
+ method = getattr(self.stream_client, "posts_firehose")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1357,7 +1363,7 @@ def test_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"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1373,12 +1379,12 @@ def test_likes_sample10_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for likes_sample10: {e}")
+ pytest.fail(f"Contract test failed for posts_firehose: {e}")
- def test_likes_sample10_required_parameters(self):
- """Test that likes_sample10 handles parameters correctly."""
- method = getattr(self.stream_client, "likes_sample10")
+ 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)
@@ -1392,8 +1398,8 @@ def test_likes_sample10_required_parameters(self):
method()
- def test_likes_sample10_response_structure(self):
- """Test likes_sample10 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 = {
@@ -1409,7 +1415,7 @@ def test_likes_sample10_response_structure(self):
kwargs["partition"] = 1
# Add request body if required
# Call method and verify response structure
- method = getattr(self.stream_client, "likes_sample10")
+ 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
@@ -1421,8 +1427,8 @@ def test_likes_sample10_response_structure(self):
)
- def test_posts_compliance_request_structure(self):
- """Test posts_compliance 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()
@@ -1439,7 +1445,7 @@ def test_posts_compliance_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.stream_client, "posts_compliance")
+ method = getattr(self.stream_client, "users_compliance")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1474,7 +1480,7 @@ def test_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/users/compliance/stream"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1490,12 +1496,12 @@ def test_posts_compliance_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for posts_compliance: {e}")
+ pytest.fail(f"Contract test failed for users_compliance: {e}")
- def test_posts_compliance_required_parameters(self):
- """Test that posts_compliance handles parameters correctly."""
- method = getattr(self.stream_client, "posts_compliance")
+ 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)
@@ -1509,8 +1515,8 @@ def test_posts_compliance_required_parameters(self):
method()
- def test_posts_compliance_response_structure(self):
- """Test posts_compliance 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 = {
@@ -1526,7 +1532,7 @@ def test_posts_compliance_response_structure(self):
kwargs["partition"] = 1
# Add request body if required
# Call method and verify response structure
- method = getattr(self.stream_client, "posts_compliance")
+ 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
@@ -1538,8 +1544,8 @@ def test_posts_compliance_response_structure(self):
)
- def test_get_rules_request_structure(self):
- """Test get_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()
@@ -1552,10 +1558,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_compliance")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1590,7 +1597,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/compliance/stream"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1606,27 +1613,27 @@ def test_get_rules_request_structure(self):
# For regular operations, verify we got a result
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_compliance: {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_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)
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_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 = {
@@ -1639,9 +1646,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_compliance")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -1653,8 +1661,8 @@ def test_get_rules_response_structure(self):
)
- def test_update_rules_request_structure(self):
- """Test update_rules 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()
@@ -1663,18 +1671,15 @@ 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_sample10")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1693,7 +1698,7 @@ def test_update_rules_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -1702,14 +1707,14 @@ def test_update_rules_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/sample10/stream"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1725,12 +1730,12 @@ def test_update_rules_request_structure(self):
# For regular operations, verify we got a result
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_sample10: {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_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)
@@ -1738,14 +1743,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_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 = {
@@ -1755,16 +1760,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_sample10")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -1776,8 +1778,8 @@ def test_update_rules_response_structure(self):
)
- def test_posts_firehose_ja_request_structure(self):
- """Test posts_firehose_ja 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()
@@ -1794,7 +1796,7 @@ def test_posts_firehose_ja_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.stream_client, "posts_firehose_ja")
+ method = getattr(self.stream_client, "posts_firehose_en")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1829,7 +1831,7 @@ def test_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/firehose/stream/lang/en"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1845,12 +1847,12 @@ def test_posts_firehose_ja_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for posts_firehose_ja: {e}")
+ pytest.fail(f"Contract test failed for posts_firehose_en: {e}")
- def test_posts_firehose_ja_required_parameters(self):
- """Test that posts_firehose_ja handles parameters correctly."""
- method = getattr(self.stream_client, "posts_firehose_ja")
+ 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)
@@ -1864,8 +1866,8 @@ def test_posts_firehose_ja_required_parameters(self):
method()
- def test_posts_firehose_ja_response_structure(self):
- """Test posts_firehose_ja 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 = {
@@ -1881,7 +1883,7 @@ def test_posts_firehose_ja_response_structure(self):
kwargs["partition"] = 1
# Add request body if required
# Call method and verify response structure
- method = getattr(self.stream_client, "posts_firehose_ja")
+ 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
@@ -1893,8 +1895,8 @@ def test_posts_firehose_ja_response_structure(self):
)
- def test_likes_firehose_request_structure(self):
- """Test likes_firehose 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()
@@ -1907,11 +1909,10 @@ def test_likes_firehose_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, "likes_firehose")
+ method = getattr(self.stream_client, "posts_sample")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1946,7 +1947,7 @@ def test_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/tweets/sample/stream"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1962,27 +1963,27 @@ def test_likes_firehose_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for likes_firehose: {e}")
+ pytest.fail(f"Contract test failed for posts_sample: {e}")
- 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
+ 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 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_likes_firehose_response_structure(self):
- """Test likes_firehose 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 = {
@@ -1995,10 +1996,9 @@ def test_likes_firehose_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, "likes_firehose")
+ 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
diff --git a/xdk/python/tests/stream/test_structure.py b/xdk/python/tests/stream/test_structure.py
index 43010e70..93de56ab 100644
--- a/xdk/python/tests/stream/test_structure.py
+++ b/xdk/python/tests/stream/test_structure.py
@@ -28,36 +28,40 @@ def setup_class(self):
self.stream_client = getattr(self.client, "stream")
- def test_posts_sample_exists(self):
- """Test that posts_sample 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, "posts_sample", None)
- assert method is not None, f"Method posts_sample does not exist on StreamClient"
+ method = getattr(StreamClient, "likes_firehose", None)
+ assert (
+ method is not None
+ ), f"Method likes_firehose does not exist on StreamClient"
# Check method is callable
- assert callable(method), f"posts_sample 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"posts_sample 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]}'"
# 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 posts_sample"
+ ), f"Required parameter '{required_param}' missing from likes_firehose"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
"backfill_minutes",
- "tweet.fields",
+ "start_time",
+ "end_time",
+ "like_with_tweet_author.fields",
"expansions",
- "media.fields",
- "poll.fields",
"user.fields",
- "place.fields",
+ "tweet.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -67,44 +71,54 @@ def test_posts_sample_exists(self):
), 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")
+ 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 posts_sample should have return type annotation"
+ ), f"Method likes_firehose should have return type annotation"
- def test_get_rule_counts_exists(self):
- """Test that get_rule_counts 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, "get_rule_counts", None)
+ method = getattr(StreamClient, "posts_firehose_pt", None)
assert (
method is not None
- ), f"Method get_rule_counts does not exist on StreamClient"
+ ), f"Method posts_firehose_pt does not exist on StreamClient"
# Check method is callable
- assert callable(method), f"get_rule_counts 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"get_rule_counts 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]}'"
# 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 get_rule_counts"
+ ), f"Required parameter '{required_param}' missing from posts_firehose_pt"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "rules_count.fields",
+ "backfill_minutes",
+ "start_time",
+ "end_time",
+ "tweet.fields",
+ "expansions",
+ "media.fields",
+ "poll.fields",
+ "user.fields",
+ "place.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -114,30 +128,32 @@ def test_get_rule_counts_exists(self):
), 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_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 get_rule_counts should have return type annotation"
+ ), f"Method posts_firehose_pt should have return type annotation"
- def test_posts_firehose_exists(self):
- """Test that posts_firehose 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, "posts_firehose", None)
+ method = getattr(StreamClient, "posts_firehose_ja", None)
assert (
method is not None
- ), f"Method posts_firehose does not exist on StreamClient"
+ ), f"Method posts_firehose_ja does not exist on StreamClient"
# Check method is callable
- assert callable(method), f"posts_firehose 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"posts_firehose should have at least 'self' parameter"
+ assert (
+ len(params) >= 1
+ ), f"posts_firehose_ja should have at least 'self' parameter"
assert (
params[0] == "self"
), f"First parameter should be 'self', got '{params[0]}'"
@@ -148,7 +164,7 @@ def test_posts_firehose_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from posts_firehose"
+ ), f"Required parameter '{required_param}' missing from posts_firehose_ja"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
"backfill_minutes",
@@ -169,54 +185,46 @@ def test_posts_firehose_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_posts_firehose_return_annotation(self):
- """Test that posts_firehose has proper return type annotation."""
- method = getattr(StreamClient, "posts_firehose")
+ 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 posts_firehose should have return type annotation"
+ ), f"Method posts_firehose_ja should have return type annotation"
- def test_posts_firehose_pt_exists(self):
- """Test that posts_firehose_pt 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, "posts_firehose_pt", None)
+ method = getattr(StreamClient, "labels_compliance", None)
assert (
method is not None
- ), f"Method posts_firehose_pt does not exist on StreamClient"
+ ), f"Method labels_compliance does not exist on StreamClient"
# Check method is callable
- assert callable(method), f"posts_firehose_pt 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"posts_firehose_pt 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 posts_firehose_pt"
+ ), f"Required parameter '{required_param}' missing from labels_compliance"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
"backfill_minutes",
"start_time",
"end_time",
- "tweet.fields",
- "expansions",
- "media.fields",
- "poll.fields",
- "user.fields",
- "place.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -226,32 +234,32 @@ def test_posts_firehose_pt_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_posts_firehose_pt_return_annotation(self):
- """Test that posts_firehose_pt has proper return type annotation."""
- method = getattr(StreamClient, "posts_firehose_pt")
+ 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 posts_firehose_pt should have return type annotation"
+ ), f"Method labels_compliance should have return type annotation"
- def test_users_compliance_exists(self):
- """Test that users_compliance 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, "users_compliance", None)
+ method = getattr(StreamClient, "posts_firehose_ko", None)
assert (
method is not None
- ), f"Method users_compliance does not exist on StreamClient"
+ ), f"Method posts_firehose_ko does not exist on StreamClient"
# Check method is callable
- assert callable(method), f"users_compliance 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"users_compliance 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]}'"
@@ -262,12 +270,18 @@ def test_users_compliance_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from users_compliance"
+ ), f"Required parameter '{required_param}' missing from posts_firehose_ko"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
"backfill_minutes",
"start_time",
"end_time",
+ "tweet.fields",
+ "expansions",
+ "media.fields",
+ "poll.fields",
+ "user.fields",
+ "place.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -277,41 +291,37 @@ def test_users_compliance_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_users_compliance_return_annotation(self):
- """Test that users_compliance has proper return type annotation."""
- method = getattr(StreamClient, "users_compliance")
+ 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 users_compliance should have return type annotation"
+ ), f"Method posts_firehose_ko should have return type annotation"
- def test_posts_sample10_exists(self):
- """Test that posts_sample10 method exists with correct signature."""
+ def test_posts_exists(self):
+ """Test that posts method exists with correct signature."""
# Check method exists
- method = getattr(StreamClient, "posts_sample10", None)
- assert (
- method is not None
- ), f"Method posts_sample10 does not exist on StreamClient"
+ 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_sample10 is not 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_sample10 should have at least 'self' 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 = [
- "partition",
- ]
+ required_params = []
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from posts_sample10"
+ ), f"Required parameter '{required_param}' missing from posts"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
"backfill_minutes",
@@ -332,14 +342,14 @@ def test_posts_sample10_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_posts_sample10_return_annotation(self):
- """Test that posts_sample10 has proper return type annotation."""
- method = getattr(StreamClient, "posts_sample10")
+ 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_sample10 should have return type annotation"
+ ), f"Method posts should have return type annotation"
def test_likes_compliance_exists(self):
@@ -391,22 +401,18 @@ def test_likes_compliance_return_annotation(self):
), f"Method likes_compliance should have return type annotation"
- def test_labels_compliance_exists(self):
- """Test that labels_compliance method exists with correct signature."""
+ def test_get_rules_exists(self):
+ """Test that get_rules method exists with correct signature."""
# Check method exists
- method = getattr(StreamClient, "labels_compliance", None)
- assert (
- method is not None
- ), f"Method labels_compliance does not exist on StreamClient"
+ 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"labels_compliance is not 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"labels_compliance should have at least 'self' 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]}'"
@@ -415,12 +421,12 @@ def test_labels_compliance_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from labels_compliance"
+ ), f"Required parameter '{required_param}' missing from get_rules"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "backfill_minutes",
- "start_time",
- "end_time",
+ "ids",
+ "max_results",
+ "pagination_token",
]
for optional_param in optional_params:
if optional_param in params:
@@ -430,54 +436,60 @@ def test_labels_compliance_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_labels_compliance_return_annotation(self):
- """Test that labels_compliance has proper return type annotation."""
- method = getattr(StreamClient, "labels_compliance")
+ 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 labels_compliance should have return type annotation"
+ ), f"Method get_rules should have return type annotation"
- def test_posts_firehose_en_exists(self):
- """Test that posts_firehose_en method exists with correct signature."""
- # Check method exists
- method = getattr(StreamClient, "posts_firehose_en", None)
+ 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 (
- method is not None
- ), f"Method posts_firehose_en does not exist on StreamClient"
+ 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"posts_firehose_en is not 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"posts_firehose_en should have at least 'self' 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 = [
- "partition",
- ]
+ required_params = []
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from posts_firehose_en"
+ ), f"Required parameter '{required_param}' missing from update_rules"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "backfill_minutes",
- "start_time",
- "end_time",
- "tweet.fields",
- "expansions",
- "media.fields",
- "poll.fields",
- "user.fields",
- "place.fields",
+ "dry_run",
+ "delete_all",
]
for optional_param in optional_params:
if optional_param in params:
@@ -487,28 +499,32 @@ def test_posts_firehose_en_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_posts_firehose_en_return_annotation(self):
- """Test that posts_firehose_en has proper return type annotation."""
- method = getattr(StreamClient, "posts_firehose_en")
+ 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 posts_firehose_en should have return type annotation"
+ ), f"Method update_rules should have return type annotation"
- def test_posts_exists(self):
- """Test that posts method exists with correct signature."""
+ def test_get_rule_counts_exists(self):
+ """Test that get_rule_counts method exists with correct signature."""
# Check method exists
- method = getattr(StreamClient, "posts", None)
- assert method is not None, f"Method posts does not exist on StreamClient"
+ 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"posts 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"posts should have at least 'self' 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]}'"
@@ -517,18 +533,10 @@ def test_posts_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from posts"
+ ), 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",
- "tweet.fields",
- "expansions",
- "media.fields",
- "poll.fields",
- "user.fields",
- "place.fields",
+ "rules_count.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -538,32 +546,30 @@ def test_posts_exists(self):
), 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")
+ 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 posts should have return type annotation"
+ ), f"Method get_rule_counts should have return type annotation"
- def test_posts_firehose_ko_exists(self):
- """Test that posts_firehose_ko 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, "posts_firehose_ko", None)
+ method = getattr(StreamClient, "likes_sample10", None)
assert (
method is not None
- ), f"Method posts_firehose_ko does not exist on StreamClient"
+ ), f"Method likes_sample10 does not exist on StreamClient"
# Check method is callable
- assert callable(method), f"posts_firehose_ko 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"posts_firehose_ko 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]}'"
@@ -574,18 +580,16 @@ def test_posts_firehose_ko_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from posts_firehose_ko"
+ ), f"Required parameter '{required_param}' missing from likes_sample10"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
"backfill_minutes",
"start_time",
"end_time",
- "tweet.fields",
+ "like_with_tweet_author.fields",
"expansions",
- "media.fields",
- "poll.fields",
"user.fields",
- "place.fields",
+ "tweet.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -595,30 +599,30 @@ def test_posts_firehose_ko_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_posts_firehose_ko_return_annotation(self):
- """Test that posts_firehose_ko has proper return type annotation."""
- method = getattr(StreamClient, "posts_firehose_ko")
+ 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 posts_firehose_ko should have return type annotation"
+ ), f"Method likes_sample10 should have return type annotation"
- def test_likes_sample10_exists(self):
- """Test that likes_sample10 method exists with correct signature."""
+ def test_posts_firehose_exists(self):
+ """Test that posts_firehose method exists with correct signature."""
# Check method exists
- method = getattr(StreamClient, "likes_sample10", None)
+ method = getattr(StreamClient, "posts_firehose", None)
assert (
method is not None
- ), f"Method likes_sample10 does not exist on StreamClient"
+ ), f"Method posts_firehose does not exist on StreamClient"
# Check method is callable
- assert callable(method), f"likes_sample10 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"likes_sample10 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]}'"
@@ -629,16 +633,18 @@ def test_likes_sample10_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from likes_sample10"
+ ), f"Required parameter '{required_param}' missing from posts_firehose"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
"backfill_minutes",
"start_time",
"end_time",
- "like_with_tweet_author.fields",
+ "tweet.fields",
"expansions",
+ "media.fields",
+ "poll.fields",
"user.fields",
- "tweet.fields",
+ "place.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -648,32 +654,32 @@ def test_likes_sample10_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_likes_sample10_return_annotation(self):
- """Test that likes_sample10 has proper return type annotation."""
- method = getattr(StreamClient, "likes_sample10")
+ 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 likes_sample10 should have return type annotation"
+ ), f"Method posts_firehose should have return type annotation"
- def test_posts_compliance_exists(self):
- """Test that posts_compliance 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, "posts_compliance", None)
+ method = getattr(StreamClient, "users_compliance", None)
assert (
method is not None
- ), f"Method posts_compliance does not exist on StreamClient"
+ ), f"Method users_compliance does not exist on StreamClient"
# Check method is callable
- assert callable(method), f"posts_compliance 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"posts_compliance 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]}'"
@@ -684,7 +690,7 @@ def test_posts_compliance_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from posts_compliance"
+ ), f"Required parameter '{required_param}' missing from users_compliance"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
"backfill_minutes",
@@ -699,42 +705,48 @@ def test_posts_compliance_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_posts_compliance_return_annotation(self):
- """Test that posts_compliance has proper return type annotation."""
- method = getattr(StreamClient, "posts_compliance")
+ 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 posts_compliance should have return type annotation"
+ ), f"Method users_compliance should have return type annotation"
- def test_get_rules_exists(self):
- """Test that get_rules 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, "get_rules", None)
- assert method is not None, f"Method get_rules does not exist on StreamClient"
+ method = getattr(StreamClient, "posts_compliance", None)
+ assert (
+ method is not None
+ ), f"Method posts_compliance does not exist on StreamClient"
# Check method is callable
- assert callable(method), f"get_rules 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"get_rules should have at least 'self' parameter"
+ assert (
+ len(params) >= 1
+ ), 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 get_rules"
+ ), f"Required parameter '{required_param}' missing from posts_compliance"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "ids",
- "max_results",
- "pagination_token",
+ "backfill_minutes",
+ "start_time",
+ "end_time",
]
for optional_param in optional_params:
if optional_param in params:
@@ -744,60 +756,52 @@ def test_get_rules_exists(self):
), 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")
+ 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 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"
+ ), f"Method posts_compliance should have return type annotation"
- def test_update_rules_exists(self):
- """Test that update_rules 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, "update_rules", None)
- assert method is not None, f"Method update_rules does not exist on StreamClient"
+ method = getattr(StreamClient, "posts_sample10", None)
+ assert (
+ method is not None
+ ), f"Method posts_sample10 does not exist on StreamClient"
# Check method is callable
- assert callable(method), f"update_rules 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"update_rules 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 = []
+ required_params = [
+ "partition",
+ ]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from update_rules"
+ ), f"Required parameter '{required_param}' missing from posts_sample10"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "dry_run",
- "delete_all",
+ "backfill_minutes",
+ "start_time",
+ "end_time",
+ "tweet.fields",
+ "expansions",
+ "media.fields",
+ "poll.fields",
+ "user.fields",
+ "place.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -807,32 +811,32 @@ def test_update_rules_exists(self):
), 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")
+ 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 update_rules should have return type annotation"
+ ), f"Method posts_sample10 should have return type annotation"
- def test_posts_firehose_ja_exists(self):
- """Test that posts_firehose_ja 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, "posts_firehose_ja", None)
+ method = getattr(StreamClient, "posts_firehose_en", None)
assert (
method is not None
- ), f"Method posts_firehose_ja does not exist on StreamClient"
+ ), f"Method posts_firehose_en does not exist on StreamClient"
# Check method is callable
- assert callable(method), f"posts_firehose_ja 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"posts_firehose_ja 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]}'"
@@ -843,7 +847,7 @@ def test_posts_firehose_ja_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from posts_firehose_ja"
+ ), f"Required parameter '{required_param}' missing from posts_firehose_en"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
"backfill_minutes",
@@ -864,50 +868,46 @@ def test_posts_firehose_ja_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_posts_firehose_ja_return_annotation(self):
- """Test that posts_firehose_ja has proper return type annotation."""
- method = getattr(StreamClient, "posts_firehose_ja")
+ 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 posts_firehose_ja should have return type annotation"
+ ), f"Method posts_firehose_en should have return type annotation"
- def test_likes_firehose_exists(self):
- """Test that likes_firehose 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, "likes_firehose", None)
- assert (
- method is not None
- ), f"Method likes_firehose does not exist on StreamClient"
+ 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"likes_firehose is not 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"likes_firehose should have at least 'self' 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 = [
- "partition",
- ]
+ required_params = []
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from likes_firehose"
+ ), f"Required parameter '{required_param}' missing from posts_sample"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
"backfill_minutes",
- "start_time",
- "end_time",
- "like_with_tweet_author.fields",
+ "tweet.fields",
"expansions",
+ "media.fields",
+ "poll.fields",
"user.fields",
- "tweet.fields",
+ "place.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -917,36 +917,36 @@ def test_likes_firehose_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_likes_firehose_return_annotation(self):
- """Test that likes_firehose has proper return type annotation."""
- method = getattr(StreamClient, "likes_firehose")
+ 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 likes_firehose should have return type annotation"
+ ), f"Method posts_sample should have return type annotation"
def test_all_expected_methods_exist(self):
"""Test that all expected methods exist on the client."""
expected_methods = [
- "posts_sample",
- "get_rule_counts",
- "posts_firehose",
+ "likes_firehose",
"posts_firehose_pt",
- "users_compliance",
- "posts_sample10",
- "likes_compliance",
+ "posts_firehose_ja",
"labels_compliance",
- "posts_firehose_en",
- "posts",
"posts_firehose_ko",
- "likes_sample10",
- "posts_compliance",
+ "posts",
+ "likes_compliance",
"get_rules",
"update_rules",
- "posts_firehose_ja",
- "likes_firehose",
+ "get_rule_counts",
+ "likes_sample10",
+ "posts_firehose",
+ "users_compliance",
+ "posts_compliance",
+ "posts_sample10",
+ "posts_firehose_en",
+ "posts_sample",
]
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 99a3229e..9079f75f 100644
--- a/xdk/python/tests/trends/test_contracts.py
+++ b/xdk/python/tests/trends/test_contracts.py
@@ -27,8 +27,8 @@ def setup_class(self):
self.trends_client = getattr(self.client, "trends")
- def test_get_personalized_request_structure(self):
- """Test get_personalized request structure."""
+ def test_get_ai_request_structure(self):
+ """Test get_ai request structure."""
# Mock the session to capture request details
with patch.object(self.client, "session") as mock_session:
mock_response = Mock()
@@ -41,10 +41,11 @@ def test_get_personalized_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.trends_client, "get_personalized")
+ method = getattr(self.trends_client, "get_ai")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -79,7 +80,7 @@ def test_get_personalized_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/ai_trends/{id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -95,27 +96,27 @@ def test_get_personalized_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_personalized: {e}")
+ pytest.fail(f"Contract test failed for get_ai: {e}")
- 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
+ def test_get_ai_required_parameters(self):
+ """Test that get_ai handles parameters correctly."""
+ method = getattr(self.trends_client, "get_ai")
+ # 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_personalized_response_structure(self):
- """Test get_personalized response structure validation."""
+ def test_get_ai_response_structure(self):
+ """Test get_ai response structure validation."""
with patch.object(self.client, "session") as mock_session:
# Create mock response with expected structure
mock_response_data = {
@@ -128,9 +129,10 @@ def test_get_personalized_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.trends_client, "get_personalized")
+ method = getattr(self.trends_client, "get_ai")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -257,3 +259,118 @@ def test_get_by_woeid_response_structure(self):
pytest.fail(
f"Accessing optional field 'data' should not cause errors: {e}"
)
+
+
+ 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()
+ 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_personalized")
+ result = method(**kwargs)
+ # Check if this is a streaming operation (returns Generator)
+ import types
+ is_streaming = isinstance(result, types.GeneratorType)
+ if is_streaming:
+ # For streaming operations, we need to set up the mock to handle streaming
+ # Mock the streaming response
+ mock_streaming_response = Mock()
+ mock_streaming_response.status_code = 200
+ mock_streaming_response.raise_for_status.return_value = None
+ mock_streaming_response.__enter__ = Mock(
+ return_value=mock_streaming_response
+ )
+ mock_streaming_response.__exit__ = Mock(return_value=None)
+ # Mock iter_content to yield some test data
+ test_data = '{"data": "test"}\n'
+ mock_streaming_response.iter_content.return_value = [test_data]
+ # Update the session mock to return our streaming response
+ mock_session.get.return_value = mock_streaming_response
+ # Consume the generator to trigger the HTTP request
+ try:
+ next(result)
+ except StopIteration:
+ pass # Expected when stream ends
+ except Exception:
+ pass # Ignore other exceptions in test data processing
+ # 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
+ if is_streaming:
+ # For streaming, verify we got a generator
+ assert isinstance(
+ result, types.GeneratorType
+ ), "Streaming method should return a generator"
+ else:
+ # For regular operations, verify we got a result
+ assert result is not None, "Method should return a result"
+ except Exception as e:
+ pytest.fail(f"Contract test failed for get_personalized: {e}")
+
+
+ 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_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_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 = {
+ "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_personalized")
+ 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/trends/test_structure.py b/xdk/python/tests/trends/test_structure.py
index 8b9a4652..63042b5f 100644
--- a/xdk/python/tests/trends/test_structure.py
+++ b/xdk/python/tests/trends/test_structure.py
@@ -28,34 +28,32 @@ def setup_class(self):
self.trends_client = getattr(self.client, "trends")
- def test_get_personalized_exists(self):
- """Test that get_personalized method exists with correct signature."""
+ def test_get_ai_exists(self):
+ """Test that get_ai method exists with correct signature."""
# Check method exists
- method = getattr(TrendsClient, "get_personalized", None)
- assert (
- method is not None
- ), f"Method get_personalized does not exist on TrendsClient"
+ method = getattr(TrendsClient, "get_ai", None)
+ assert method is not None, f"Method get_ai does not exist on TrendsClient"
# Check method is callable
- assert callable(method), f"get_personalized is not callable"
+ assert callable(method), f"get_ai is not 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_personalized should have at least 'self' parameter"
+ assert len(params) >= 1, f"get_ai 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_personalized"
+ ), f"Required parameter '{required_param}' missing from get_ai"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "personalized_trend.fields",
+ "news.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -65,14 +63,14 @@ def test_get_personalized_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_personalized_return_annotation(self):
- """Test that get_personalized has proper return type annotation."""
- method = getattr(TrendsClient, "get_personalized")
+ def test_get_ai_return_annotation(self):
+ """Test that get_ai has proper return type annotation."""
+ method = getattr(TrendsClient, "get_ai")
sig = inspect.signature(method)
# Check return annotation exists
assert (
sig.return_annotation is not inspect.Signature.empty
- ), f"Method get_personalized should have return type annotation"
+ ), f"Method get_ai should have return type annotation"
def test_get_by_woeid_exists(self):
@@ -121,11 +119,59 @@ def test_get_by_woeid_return_annotation(self):
), f"Method get_by_woeid should have return type annotation"
+ def test_get_personalized_exists(self):
+ """Test that get_personalized method exists with correct signature."""
+ # Check method exists
+ method = getattr(TrendsClient, "get_personalized", None)
+ assert (
+ method is not None
+ ), f"Method get_personalized does not exist on TrendsClient"
+ # Check method is 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_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 = []
+ for required_param in required_params:
+ assert (
+ required_param in params
+ ), f"Required parameter '{required_param}' missing from get_personalized"
+ # Check optional parameters have defaults (excluding 'self')
+ optional_params = [
+ "personalized_trend.fields",
+ ]
+ 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_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_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_personalized",
+ "get_ai",
"get_by_woeid",
+ "get_personalized",
]
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 92902805..fd1f53d9 100644
--- a/xdk/python/tests/users/test_contracts.py
+++ b/xdk/python/tests/users/test_contracts.py
@@ -27,8 +27,8 @@ def setup_class(self):
self.users_client = getattr(self.client, "users")
- def test_get_me_request_structure(self):
- """Test get_me 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()
@@ -37,14 +37,19 @@ def test_get_me_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 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, "get_me")
+ method = getattr(self.users_client, "like_post")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -63,7 +68,7 @@ def test_get_me_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -72,14 +77,14 @@ def test_get_me_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/me"
+ expected_path = "/2/users/{id}/likes"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -95,27 +100,27 @@ def test_get_me_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_me: {e}")
+ pytest.fail(f"Contract test failed for like_post: {e}")
- 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
+ def test_like_post_required_parameters(self):
+ """Test that like_post handles parameters correctly."""
+ method = getattr(self.users_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 = 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_me_response_structure(self):
- """Test get_me 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 = {
@@ -125,12 +130,17 @@ def test_get_me_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 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, "get_me")
+ method = getattr(self.users_client, "like_post")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -142,8 +152,8 @@ def test_get_me_response_structure(self):
)
- def test_unfollow_list_request_structure(self):
- """Test unfollow_list 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()
@@ -157,11 +167,11 @@ def test_unfollow_list_request_structure(self):
kwargs = {}
# Add required parameters
kwargs["id"] = "test_value"
- kwargs["list_id"] = "test_value"
+ kwargs["tweet_id"] = "test_value"
# Add request body if required
# Call the method
try:
- method = getattr(self.users_client, "unfollow_list")
+ method = getattr(self.users_client, "unlike_post")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -196,7 +206,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}/likes/{tweet_id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -212,12 +222,12 @@ def test_unfollow_list_request_structure(self):
# For regular operations, verify we got a result
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 unlike_post: {e}")
- def test_unfollow_list_required_parameters(self):
- """Test that unfollow_list handles parameters correctly."""
- method = getattr(self.users_client, "unfollow_list")
+ def test_unlike_post_required_parameters(self):
+ """Test that unlike_post handles parameters correctly."""
+ method = getattr(self.users_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)
@@ -231,8 +241,8 @@ def test_unfollow_list_required_parameters(self):
method()
- def test_unfollow_list_response_structure(self):
- """Test unfollow_list 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 = {
@@ -246,10 +256,10 @@ def test_unfollow_list_response_structure(self):
# Prepare minimal valid parameters
kwargs = {}
kwargs["id"] = "test"
- kwargs["list_id"] = "test"
+ kwargs["tweet_id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.users_client, "unfollow_list")
+ method = getattr(self.users_client, "unlike_post")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -503,8 +513,8 @@ def test_mute_user_response_structure(self):
)
- def test_unlike_post_request_structure(self):
- """Test unlike_post request structure."""
+ def test_get_pinned_lists_request_structure(self):
+ """Test get_pinned_lists request structure."""
# Mock the session to capture request details
with patch.object(self.client, "session") as mock_session:
mock_response = Mock()
@@ -513,16 +523,15 @@ def test_unlike_post_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["tweet_id"] = "test_value"
# Add request body if required
# Call the method
try:
- method = getattr(self.users_client, "unlike_post")
+ method = getattr(self.users_client, "get_pinned_lists")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -541,7 +550,7 @@ def test_unlike_post_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.delete.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -550,14 +559,14 @@ def test_unlike_post_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/{id}/likes/{tweet_id}"
+ expected_path = "/2/users/{id}/pinned_lists"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -573,12 +582,12 @@ def test_unlike_post_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for unlike_post: {e}")
+ pytest.fail(f"Contract test failed for get_pinned_lists: {e}")
- def test_unlike_post_required_parameters(self):
- """Test that unlike_post handles parameters correctly."""
- method = getattr(self.users_client, "unlike_post")
+ def test_get_pinned_lists_required_parameters(self):
+ """Test that get_pinned_lists handles parameters correctly."""
+ method = getattr(self.users_client, "get_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)
@@ -586,14 +595,14 @@ def test_unlike_post_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_unlike_post_response_structure(self):
- """Test unlike_post response structure validation."""
+ def test_get_pinned_lists_response_structure(self):
+ """Test get_pinned_lists response structure validation."""
with patch.object(self.client, "session") as mock_session:
# Create mock response with expected structure
mock_response_data = {
@@ -603,14 +612,13 @@ def test_unlike_post_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["tweet_id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.users_client, "unlike_post")
+ method = getattr(self.users_client, "get_pinned_lists")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -622,8 +630,8 @@ def test_unlike_post_response_structure(self):
)
- def test_get_posts_request_structure(self):
- """Test get_posts 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()
@@ -632,15 +640,19 @@ def test_get_posts_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 PinListRequest
+ # Create instance with minimal valid data (empty instance should work for most cases)
+ kwargs["body"] = PinListRequest()
# Call the method
try:
- method = getattr(self.users_client, "get_posts")
+ method = getattr(self.users_client, "pin_list")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -659,7 +671,7 @@ def test_get_posts_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -668,14 +680,14 @@ def test_get_posts_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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}/tweets"
+ expected_path = "/2/users/{id}/pinned_lists"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -691,12 +703,12 @@ def test_get_posts_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_posts: {e}")
+ pytest.fail(f"Contract test failed for pin_list: {e}")
- def test_get_posts_required_parameters(self):
- """Test that get_posts handles parameters correctly."""
- method = getattr(self.users_client, "get_posts")
+ def test_pin_list_required_parameters(self):
+ """Test that pin_list handles parameters correctly."""
+ method = getattr(self.users_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)
@@ -704,14 +716,14 @@ def test_get_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.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_posts_response_structure(self):
- """Test get_posts 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 = {
@@ -721,13 +733,17 @@ def test_get_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.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 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.users_client, "get_posts")
+ method = getattr(self.users_client, "pin_list")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -739,8 +755,8 @@ def test_get_posts_response_structure(self):
)
- def test_get_following_request_structure(self):
- """Test get_following 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()
@@ -749,15 +765,16 @@ def test_get_following_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_following")
+ method = getattr(self.users_client, "unrepost_post")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -776,7 +793,7 @@ def test_get_following_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.delete.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -785,14 +802,14 @@ def test_get_following_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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}/following"
+ expected_path = "/2/users/{id}/retweets/{source_tweet_id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -808,12 +825,12 @@ def test_get_following_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_following: {e}")
+ pytest.fail(f"Contract test failed for unrepost_post: {e}")
- def test_get_following_required_parameters(self):
- """Test that get_following handles parameters correctly."""
- method = getattr(self.users_client, "get_following")
+ def test_unrepost_post_required_parameters(self):
+ """Test that unrepost_post handles parameters correctly."""
+ method = getattr(self.users_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)
@@ -821,14 +838,14 @@ def test_get_following_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_following_response_structure(self):
- """Test get_following 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 = {
@@ -838,13 +855,14 @@ def test_get_following_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_following")
+ method = getattr(self.users_client, "unrepost_post")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -856,8 +874,8 @@ def test_get_following_response_structure(self):
)
- def test_follow_user_request_structure(self):
- """Test follow_user 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()
@@ -866,19 +884,16 @@ 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.delete.return_value = mock_response
# Prepare test parameters
kwargs = {}
# Add required parameters
- kwargs["id"] = "test_value"
+ kwargs["source_user_id"] = "test_value"
+ kwargs["target_user_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.users_client, "unmute_user")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -897,7 +912,7 @@ def test_follow_user_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.delete.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -906,14 +921,14 @@ def test_follow_user_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/users/{id}/following"
+ expected_path = "/2/users/{source_user_id}/muting/{target_user_id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -929,12 +944,12 @@ def test_follow_user_request_structure(self):
# For regular operations, verify we got a result
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 unmute_user: {e}")
- def test_follow_user_required_parameters(self):
- """Test that follow_user handles parameters correctly."""
- method = getattr(self.users_client, "follow_user")
+ 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)
@@ -942,14 +957,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.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_follow_user_response_structure(self):
- """Test follow_user 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 = {
@@ -959,17 +974,14 @@ 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.delete.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
- kwargs["id"] = "test"
+ kwargs["source_user_id"] = "test"
+ kwargs["target_user_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.users_client, "unmute_user")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -981,8 +993,8 @@ def test_follow_user_response_structure(self):
)
- def test_get_timeline_request_structure(self):
- """Test get_timeline request structure."""
+ def test_delete_bookmark_request_structure(self):
+ """Test delete_bookmark request structure."""
# Mock the session to capture request details
with patch.object(self.client, "session") as mock_session:
mock_response = Mock()
@@ -991,15 +1003,16 @@ def test_get_timeline_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_timeline")
+ method = getattr(self.users_client, "delete_bookmark")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1018,7 +1031,7 @@ def test_get_timeline_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.delete.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -1027,14 +1040,14 @@ def test_get_timeline_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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}/timelines/reverse_chronological"
+ expected_path = "/2/users/{id}/bookmarks/{tweet_id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1050,12 +1063,12 @@ def test_get_timeline_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_timeline: {e}")
+ pytest.fail(f"Contract test failed for delete_bookmark: {e}")
- def test_get_timeline_required_parameters(self):
- """Test that get_timeline handles parameters correctly."""
- method = getattr(self.users_client, "get_timeline")
+ def test_delete_bookmark_required_parameters(self):
+ """Test that delete_bookmark handles parameters correctly."""
+ method = getattr(self.users_client, "delete_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)
@@ -1063,14 +1076,14 @@ def test_get_timeline_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_timeline_response_structure(self):
- """Test get_timeline response structure validation."""
+ def test_delete_bookmark_response_structure(self):
+ """Test delete_bookmark response structure validation."""
with patch.object(self.client, "session") as mock_session:
# Create mock response with expected structure
mock_response_data = {
@@ -1080,13 +1093,14 @@ def test_get_timeline_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_timeline")
+ method = getattr(self.users_client, "delete_bookmark")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -1098,8 +1112,8 @@ def test_get_timeline_response_structure(self):
)
- def test_unmute_user_request_structure(self):
- """Test unmute_user 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()
@@ -1108,16 +1122,15 @@ 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_list_memberships")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1136,7 +1149,7 @@ def test_unmute_user_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.delete.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -1145,14 +1158,14 @@ def test_unmute_user_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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}/list_memberships"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1168,12 +1181,12 @@ def test_unmute_user_request_structure(self):
# For regular operations, verify we got a result
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_list_memberships: {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_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)
@@ -1181,14 +1194,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_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 = {
@@ -1198,14 +1211,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_list_memberships")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -1217,8 +1229,8 @@ def test_unmute_user_response_structure(self):
)
- def test_search_request_structure(self):
- """Test search 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()
@@ -1231,11 +1243,10 @@ def test_search_request_structure(self):
# Prepare test parameters
kwargs = {}
# Add required parameters
- kwargs["query"] = "test_value"
# Add request body if required
# Call the method
try:
- method = getattr(self.users_client, "search")
+ method = getattr(self.users_client, "get_me")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1270,7 +1281,7 @@ def test_search_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/users/me"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1286,27 +1297,27 @@ def test_search_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for search: {e}")
+ pytest.fail(f"Contract test failed for get_me: {e}")
- 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
+ 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_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_search_response_structure(self):
- """Test search 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 = {
@@ -1319,10 +1330,9 @@ def test_search_response_structure(self):
mock_session.get.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
- kwargs["query"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.users_client, "search")
+ 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
@@ -1334,8 +1344,8 @@ def test_search_response_structure(self):
)
- def test_get_owned_lists_request_structure(self):
- """Test get_owned_lists request structure."""
+ 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()
@@ -1352,7 +1362,7 @@ def test_get_owned_lists_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.users_client, "get_owned_lists")
+ method = getattr(self.users_client, "get_liked_posts")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1387,7 +1397,7 @@ def test_get_owned_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}/owned_lists"
+ expected_path = "/2/users/{id}/liked_tweets"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1403,12 +1413,12 @@ def test_get_owned_lists_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_owned_lists: {e}")
+ pytest.fail(f"Contract test failed for get_liked_posts: {e}")
- def test_get_owned_lists_required_parameters(self):
- """Test that get_owned_lists handles parameters correctly."""
- method = getattr(self.users_client, "get_owned_lists")
+ 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)
@@ -1422,8 +1432,8 @@ def test_get_owned_lists_required_parameters(self):
method()
- def test_get_owned_lists_response_structure(self):
- """Test get_owned_lists response structure validation."""
+ 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 = {
@@ -1439,7 +1449,7 @@ def test_get_owned_lists_response_structure(self):
kwargs["id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.users_client, "get_owned_lists")
+ 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
@@ -1451,8 +1461,8 @@ def test_get_owned_lists_response_structure(self):
)
- def test_get_by_usernames_request_structure(self):
- """Test get_by_usernames 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()
@@ -1465,11 +1475,11 @@ def test_get_by_usernames_request_structure(self):
# Prepare test parameters
kwargs = {}
# Add required parameters
- kwargs["usernames"] = ["test_item"]
+ kwargs["id"] = "test_value"
# Add request body if required
# Call the method
try:
- method = getattr(self.users_client, "get_by_usernames")
+ method = getattr(self.users_client, "get_posts")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1504,7 +1514,7 @@ def test_get_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/users/{id}/tweets"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1520,12 +1530,12 @@ def test_get_by_usernames_request_structure(self):
# For regular operations, verify we got a result
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}")
+ pytest.fail(f"Contract test failed for get_posts: {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")
+ 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)
@@ -1539,8 +1549,8 @@ def test_get_by_usernames_required_parameters(self):
method()
- def test_get_by_usernames_response_structure(self):
- """Test get_by_usernames 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 = {
@@ -1553,10 +1563,10 @@ def test_get_by_usernames_response_structure(self):
mock_session.get.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
- kwargs["usernames"] = ["test"]
+ kwargs["id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.users_client, "get_by_usernames")
+ 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
@@ -1568,8 +1578,8 @@ def test_get_by_usernames_response_structure(self):
)
- def test_get_mentions_request_structure(self):
- """Test get_mentions 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()
@@ -1586,7 +1596,7 @@ def test_get_mentions_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.users_client, "get_mentions")
+ method = getattr(self.users_client, "get_followed_lists")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1621,7 +1631,7 @@ def test_get_mentions_request_structure(self):
called_url = (
call_args[0][0] if call_args[0] else call_args[1].get("url", "")
)
- expected_path = "/2/users/{id}/mentions"
+ expected_path = "/2/users/{id}/followed_lists"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1637,12 +1647,12 @@ def test_get_mentions_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_mentions: {e}")
+ pytest.fail(f"Contract test failed for get_followed_lists: {e}")
- def test_get_mentions_required_parameters(self):
- """Test that get_mentions handles parameters correctly."""
- method = getattr(self.users_client, "get_mentions")
+ 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)
@@ -1656,8 +1666,8 @@ def test_get_mentions_required_parameters(self):
method()
- def test_get_mentions_response_structure(self):
- """Test get_mentions 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 = {
@@ -1673,7 +1683,7 @@ def test_get_mentions_response_structure(self):
kwargs["id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.users_client, "get_mentions")
+ 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
@@ -1685,8 +1695,8 @@ def test_get_mentions_response_structure(self):
)
- def test_get_list_memberships_request_structure(self):
- """Test get_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()
@@ -1695,15 +1705,19 @@ def test_get_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.users.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.users_client, "get_list_memberships")
+ method = getattr(self.users_client, "follow_list")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1722,7 +1736,7 @@ def test_get_list_memberships_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -1731,14 +1745,14 @@ def test_get_list_memberships_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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(
@@ -1754,12 +1768,12 @@ def test_get_list_memberships_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_list_memberships: {e}")
+ pytest.fail(f"Contract test failed for follow_list: {e}")
- def test_get_list_memberships_required_parameters(self):
- """Test that get_list_memberships handles parameters correctly."""
- method = getattr(self.users_client, "get_list_memberships")
+ def test_follow_list_required_parameters(self):
+ """Test that follow_list handles parameters correctly."""
+ method = getattr(self.users_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)
@@ -1767,14 +1781,14 @@ def test_get_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_list_memberships_response_structure(self):
- """Test get_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 = {
@@ -1784,13 +1798,17 @@ def test_get_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.users.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.users_client, "get_list_memberships")
+ method = getattr(self.users_client, "follow_list")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -1802,8 +1820,8 @@ def test_get_list_memberships_response_structure(self):
)
- def test_get_blocking_request_structure(self):
- """Test get_blocking 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()
@@ -1816,11 +1834,11 @@ def test_get_blocking_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_blocking")
+ method = getattr(self.users_client, "get_by_username")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1855,7 +1873,7 @@ def test_get_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/users/by/username/{username}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1871,12 +1889,12 @@ def test_get_blocking_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_blocking: {e}")
+ pytest.fail(f"Contract test failed for get_by_username: {e}")
- def test_get_blocking_required_parameters(self):
- """Test that get_blocking handles parameters correctly."""
- method = getattr(self.users_client, "get_blocking")
+ 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)
@@ -1890,8 +1908,8 @@ def test_get_blocking_required_parameters(self):
method()
- def test_get_blocking_response_structure(self):
- """Test get_blocking 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 = {
@@ -1904,10 +1922,10 @@ def test_get_blocking_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_blocking")
+ 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
@@ -1919,8 +1937,8 @@ def test_get_blocking_response_structure(self):
)
- def test_get_followed_lists_request_structure(self):
- """Test get_followed_lists 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()
@@ -1937,7 +1955,7 @@ def test_get_followed_lists_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.users_client, "get_followed_lists")
+ method = getattr(self.users_client, "get_mentions")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -1972,7 +1990,7 @@ def test_get_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/users/{id}/mentions"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -1988,13 +2006,13 @@ def test_get_followed_lists_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_followed_lists: {e}")
+ pytest.fail(f"Contract test failed for get_mentions: {e}")
- 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
+ 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()
@@ -2007,8 +2025,8 @@ def test_get_followed_lists_required_parameters(self):
method()
- def test_get_followed_lists_response_structure(self):
- """Test get_followed_lists 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 = {
@@ -2024,7 +2042,7 @@ def test_get_followed_lists_response_structure(self):
kwargs["id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.users_client, "get_followed_lists")
+ 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
@@ -2036,8 +2054,8 @@ def test_get_followed_lists_response_structure(self):
)
- def test_follow_list_request_structure(self):
- """Test follow_list request structure."""
+ 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()
@@ -2046,19 +2064,15 @@ 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.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 FollowListRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = FollowListRequest()
# Call the method
try:
- method = getattr(self.users_client, "follow_list")
+ method = getattr(self.users_client, "get_owned_lists")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -2077,7 +2091,7 @@ def test_follow_list_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -2086,14 +2100,14 @@ def test_follow_list_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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}/followed_lists"
+ expected_path = "/2/users/{id}/owned_lists"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -2109,12 +2123,12 @@ def test_follow_list_request_structure(self):
# For regular operations, verify we got a result
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 get_owned_lists: {e}")
- def test_follow_list_required_parameters(self):
- """Test that follow_list handles parameters correctly."""
- method = getattr(self.users_client, "follow_list")
+ 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)
@@ -2122,14 +2136,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.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_list_response_structure(self):
- """Test follow_list 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 = {
@@ -2139,17 +2153,13 @@ 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.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 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.users_client, "follow_list")
+ 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
@@ -2161,8 +2171,8 @@ def test_follow_list_response_structure(self):
)
- def test_unrepost_post_request_structure(self):
- """Test unrepost_post 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()
@@ -2171,16 +2181,19 @@ def test_unrepost_post_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"
- kwargs["source_tweet_id"] = "test_value"
# Add request body if required
+ # Import and create proper request model instance
+ from xdk.users.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, "unrepost_post")
+ method = getattr(self.users_client, "repost_post")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -2199,7 +2212,7 @@ def test_unrepost_post_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.delete.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -2208,14 +2221,14 @@ def test_unrepost_post_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/users/{id}/retweets/{source_tweet_id}"
+ expected_path = "/2/users/{id}/retweets"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -2231,12 +2244,12 @@ def test_unrepost_post_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for unrepost_post: {e}")
+ pytest.fail(f"Contract test failed for repost_post: {e}")
- def test_unrepost_post_required_parameters(self):
- """Test that unrepost_post handles parameters correctly."""
- method = getattr(self.users_client, "unrepost_post")
+ def test_repost_post_required_parameters(self):
+ """Test that repost_post handles parameters correctly."""
+ method = getattr(self.users_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)
@@ -2244,14 +2257,14 @@ def test_unrepost_post_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_unrepost_post_response_structure(self):
- """Test unrepost_post 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 = {
@@ -2261,14 +2274,17 @@ def test_unrepost_post_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"
- kwargs["source_tweet_id"] = "test"
# Add request body if required
+ # Import and create proper request model instance
+ from xdk.users.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, "unrepost_post")
+ method = getattr(self.users_client, "repost_post")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -2280,8 +2296,8 @@ def test_unrepost_post_response_structure(self):
)
- def test_get_reposts_of_me_request_structure(self):
- """Test get_reposts_of_me 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()
@@ -2290,14 +2306,16 @@ def test_get_reposts_of_me_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["list_id"] = "test_value"
# Add request body if required
# Call the method
try:
- method = getattr(self.users_client, "get_reposts_of_me")
+ method = getattr(self.users_client, "unfollow_list")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -2316,7 +2334,7 @@ def test_get_reposts_of_me_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.delete.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -2325,14 +2343,14 @@ def test_get_reposts_of_me_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/reposts_of_me"
+ expected_path = "/2/users/{id}/followed_lists/{list_id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -2348,27 +2366,27 @@ def test_get_reposts_of_me_request_structure(self):
# For regular operations, verify we got a result
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}")
+ pytest.fail(f"Contract test failed for unfollow_list: {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
+ def test_unfollow_list_required_parameters(self):
+ """Test that unfollow_list handles parameters correctly."""
+ method = getattr(self.users_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 = 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_reposts_of_me_response_structure(self):
- """Test get_reposts_of_me 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 = {
@@ -2378,12 +2396,14 @@ def test_get_reposts_of_me_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["list_id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.users_client, "get_reposts_of_me")
+ method = getattr(self.users_client, "unfollow_list")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -2395,8 +2415,8 @@ def test_get_reposts_of_me_response_structure(self):
)
- def test_get_bookmarks_request_structure(self):
- """Test get_bookmarks 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()
@@ -2409,11 +2429,11 @@ def test_get_bookmarks_request_structure(self):
# Prepare test parameters
kwargs = {}
# Add required parameters
- kwargs["id"] = "test_value"
+ kwargs["ids"] = ["test_item"]
# Add request body if required
# Call the method
try:
- method = getattr(self.users_client, "get_bookmarks")
+ method = getattr(self.users_client, "get_by_ids")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -2448,7 +2468,7 @@ def test_get_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"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -2464,12 +2484,12 @@ def test_get_bookmarks_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_bookmarks: {e}")
+ pytest.fail(f"Contract test failed for get_by_ids: {e}")
- def test_get_bookmarks_required_parameters(self):
- """Test that get_bookmarks handles parameters correctly."""
- method = getattr(self.users_client, "get_bookmarks")
+ 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)
@@ -2483,8 +2503,8 @@ def test_get_bookmarks_required_parameters(self):
method()
- def test_get_bookmarks_response_structure(self):
- """Test get_bookmarks 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 = {
@@ -2497,10 +2517,10 @@ def test_get_bookmarks_response_structure(self):
mock_session.get.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
- kwargs["id"] = "test"
+ kwargs["ids"] = ["test"]
# Add request body if required
# Call method and verify response structure
- method = getattr(self.users_client, "get_bookmarks")
+ 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
@@ -2512,8 +2532,8 @@ def test_get_bookmarks_response_structure(self):
)
- def test_create_bookmark_request_structure(self):
- """Test create_bookmark request structure."""
+ def test_get_bookmarks_by_folder_id_request_structure(self):
+ """Test get_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()
@@ -2522,19 +2542,16 @@ def test_create_bookmark_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["folder_id"] = "test_value"
# Add request body if required
- # Import and create proper request model instance
- from xdk.users.models import CreateBookmarkRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = CreateBookmarkRequest()
# Call the method
try:
- method = getattr(self.users_client, "create_bookmark")
+ method = getattr(self.users_client, "get_bookmarks_by_folder_id")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -2553,7 +2570,7 @@ def test_create_bookmark_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -2562,14 +2579,14 @@ def test_create_bookmark_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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}/bookmarks"
+ expected_path = "/2/users/{id}/bookmarks/folders/{folder_id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -2585,12 +2602,12 @@ def test_create_bookmark_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for create_bookmark: {e}")
+ pytest.fail(f"Contract test failed for get_bookmarks_by_folder_id: {e}")
- def test_create_bookmark_required_parameters(self):
- """Test that create_bookmark handles parameters correctly."""
- method = getattr(self.users_client, "create_bookmark")
+ def test_get_bookmarks_by_folder_id_required_parameters(self):
+ """Test that get_bookmarks_by_folder_id handles parameters correctly."""
+ method = getattr(self.users_client, "get_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)
@@ -2598,14 +2615,14 @@ def test_create_bookmark_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_bookmark_response_structure(self):
- """Test create_bookmark response structure validation."""
+ def test_get_bookmarks_by_folder_id_response_structure(self):
+ """Test get_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 = {
@@ -2615,17 +2632,14 @@ def test_create_bookmark_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["folder_id"] = "test"
# Add request body if required
- # Import and create proper request model instance
- from xdk.users.models import CreateBookmarkRequest
- # Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = CreateBookmarkRequest()
# Call method and verify response structure
- method = getattr(self.users_client, "create_bookmark")
+ method = getattr(self.users_client, "get_bookmarks_by_folder_id")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -2637,8 +2651,8 @@ def test_create_bookmark_response_structure(self):
)
- def test_get_by_ids_request_structure(self):
- """Test get_by_ids 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()
@@ -2647,15 +2661,15 @@ def test_get_by_ids_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["ids"] = ["test_item"]
+ kwargs["id"] = "test_value"
# Add request body if required
# Call the method
try:
- method = getattr(self.users_client, "get_by_ids")
+ method = getattr(self.users_client, "unblock_dms")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -2674,7 +2688,7 @@ def test_get_by_ids_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -2683,14 +2697,14 @@ def test_get_by_ids_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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"
+ expected_path = "/2/users/{id}/dm/unblock"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -2706,12 +2720,12 @@ def test_get_by_ids_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_by_ids: {e}")
+ pytest.fail(f"Contract test failed for unblock_dms: {e}")
- def test_get_by_ids_required_parameters(self):
- """Test that get_by_ids handles parameters correctly."""
- method = getattr(self.users_client, "get_by_ids")
+ 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)
@@ -2719,14 +2733,14 @@ def test_get_by_ids_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_by_ids_response_structure(self):
- """Test get_by_ids 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 = {
@@ -2736,13 +2750,13 @@ def test_get_by_ids_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["ids"] = ["test"]
+ kwargs["id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.users_client, "get_by_ids")
+ 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
@@ -2754,8 +2768,8 @@ def test_get_by_ids_response_structure(self):
)
- def test_get_by_id_request_structure(self):
- """Test get_by_id 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()
@@ -2772,7 +2786,7 @@ def test_get_by_id_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.users_client, "get_by_id")
+ method = getattr(self.users_client, "get_blocking")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -2807,7 +2821,7 @@ def test_get_by_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}"
+ expected_path = "/2/users/{id}/blocking"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -2823,12 +2837,12 @@ def test_get_by_id_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_by_id: {e}")
+ pytest.fail(f"Contract test failed for get_blocking: {e}")
- def test_get_by_id_required_parameters(self):
- """Test that get_by_id handles parameters correctly."""
- method = getattr(self.users_client, "get_by_id")
+ 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)
@@ -2842,8 +2856,8 @@ def test_get_by_id_required_parameters(self):
method()
- def test_get_by_id_response_structure(self):
- """Test get_by_id 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 = {
@@ -2859,7 +2873,7 @@ def test_get_by_id_response_structure(self):
kwargs["id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.users_client, "get_by_id")
+ 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
@@ -2871,8 +2885,8 @@ def test_get_by_id_response_structure(self):
)
- def test_get_bookmark_folders_request_structure(self):
- """Test get_bookmark_folders request structure."""
+ 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()
@@ -2885,11 +2899,11 @@ def test_get_bookmark_folders_request_structure(self):
# Prepare test parameters
kwargs = {}
# Add required parameters
- kwargs["id"] = "test_value"
+ kwargs["usernames"] = ["test_item"]
# Add request body if required
# Call the method
try:
- method = getattr(self.users_client, "get_bookmark_folders")
+ method = getattr(self.users_client, "get_by_usernames")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -2924,7 +2938,7 @@ def test_get_bookmark_folders_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"
+ expected_path = "/2/users/by"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -2940,12 +2954,12 @@ def test_get_bookmark_folders_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_bookmark_folders: {e}")
+ pytest.fail(f"Contract test failed for get_by_usernames: {e}")
- def test_get_bookmark_folders_required_parameters(self):
- """Test that get_bookmark_folders handles parameters correctly."""
- method = getattr(self.users_client, "get_bookmark_folders")
+ 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)
@@ -2959,8 +2973,8 @@ def test_get_bookmark_folders_required_parameters(self):
method()
- def test_get_bookmark_folders_response_structure(self):
- """Test get_bookmark_folders 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 = {
@@ -2973,10 +2987,10 @@ def test_get_bookmark_folders_response_structure(self):
mock_session.get.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
- kwargs["id"] = "test"
+ kwargs["usernames"] = ["test"]
# Add request body if required
# Call method and verify response structure
- method = getattr(self.users_client, "get_bookmark_folders")
+ 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
@@ -2988,8 +3002,8 @@ def test_get_bookmark_folders_response_structure(self):
)
- def test_unblock_dms_request_structure(self):
- """Test unblock_dms 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()
@@ -2998,15 +3012,16 @@ def test_unblock_dms_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["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, "unblock_dms")
+ method = getattr(self.users_client, "unfollow_user")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -3025,7 +3040,7 @@ def test_unblock_dms_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.delete.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -3034,14 +3049,14 @@ def test_unblock_dms_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/users/{id}/dm/unblock"
+ expected_path = "/2/users/{source_user_id}/following/{target_user_id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -3057,12 +3072,12 @@ def test_unblock_dms_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for unblock_dms: {e}")
+ pytest.fail(f"Contract test failed for unfollow_user: {e}")
- def test_unblock_dms_required_parameters(self):
- """Test that unblock_dms handles parameters correctly."""
- method = getattr(self.users_client, "unblock_dms")
+ 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)
@@ -3070,14 +3085,14 @@ def test_unblock_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.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_unblock_dms_response_structure(self):
- """Test unblock_dms 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 = {
@@ -3087,13 +3102,14 @@ def test_unblock_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.delete.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
- kwargs["id"] = "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, "unblock_dms")
+ 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
@@ -3105,8 +3121,8 @@ def test_unblock_dms_response_structure(self):
)
- def test_get_pinned_lists_request_structure(self):
- """Test get_pinned_lists 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()
@@ -3115,7 +3131,7 @@ def test_get_pinned_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
@@ -3123,7 +3139,7 @@ def test_get_pinned_lists_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.users_client, "get_pinned_lists")
+ method = getattr(self.users_client, "block_dms")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -3142,7 +3158,7 @@ def test_get_pinned_lists_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -3151,14 +3167,14 @@ def test_get_pinned_lists_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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}/pinned_lists"
+ expected_path = "/2/users/{id}/dm/block"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -3174,12 +3190,12 @@ def test_get_pinned_lists_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_pinned_lists: {e}")
+ pytest.fail(f"Contract test failed for block_dms: {e}")
- def test_get_pinned_lists_required_parameters(self):
- """Test that get_pinned_lists handles parameters correctly."""
- method = getattr(self.users_client, "get_pinned_lists")
+ 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)
@@ -3187,14 +3203,14 @@ def test_get_pinned_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_pinned_lists_response_structure(self):
- """Test get_pinned_lists 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 = {
@@ -3204,13 +3220,13 @@ def test_get_pinned_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
# Call method and verify response structure
- method = getattr(self.users_client, "get_pinned_lists")
+ 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
@@ -3222,8 +3238,8 @@ def test_get_pinned_lists_response_structure(self):
)
- def test_pin_list_request_structure(self):
- """Test pin_list 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()
@@ -3232,19 +3248,15 @@ 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.users.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.users_client, "pin_list")
+ method = getattr(self.users_client, "get_followers")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -3263,7 +3275,7 @@ def test_pin_list_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -3272,14 +3284,14 @@ def test_pin_list_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/users/{id}/followers"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -3295,12 +3307,12 @@ def test_pin_list_request_structure(self):
# For regular operations, verify we got a result
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_followers: {e}")
- def test_pin_list_required_parameters(self):
- """Test that pin_list handles parameters correctly."""
- method = getattr(self.users_client, "pin_list")
+ 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)
@@ -3308,14 +3320,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_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 = {
@@ -3325,17 +3337,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.users.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.users_client, "pin_list")
+ 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
@@ -3347,8 +3355,8 @@ def test_pin_list_response_structure(self):
)
- def test_get_liked_posts_request_structure(self):
- """Test get_liked_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()
@@ -3365,7 +3373,7 @@ def test_get_liked_posts_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.users_client, "get_liked_posts")
+ method = getattr(self.users_client, "get_by_id")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -3400,7 +3408,7 @@ def test_get_liked_posts_request_structure(self):
called_url = (
call_args[0][0] if call_args[0] else call_args[1].get("url", "")
)
- expected_path = "/2/users/{id}/liked_tweets"
+ expected_path = "/2/users/{id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -3416,12 +3424,12 @@ def test_get_liked_posts_request_structure(self):
# For regular operations, verify we got a result
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}")
+ pytest.fail(f"Contract test failed for get_by_id: {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")
+ 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)
@@ -3435,8 +3443,8 @@ def test_get_liked_posts_required_parameters(self):
method()
- def test_get_liked_posts_response_structure(self):
- """Test get_liked_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 = {
@@ -3452,7 +3460,7 @@ def test_get_liked_posts_response_structure(self):
kwargs["id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.users_client, "get_liked_posts")
+ 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
@@ -3464,8 +3472,8 @@ def test_get_liked_posts_response_structure(self):
)
- def test_get_bookmarks_by_folder_id_request_structure(self):
- """Test get_bookmarks_by_folder_id request structure."""
+ def test_get_bookmark_folders_request_structure(self):
+ """Test get_bookmark_folders request structure."""
# Mock the session to capture request details
with patch.object(self.client, "session") as mock_session:
mock_response = Mock()
@@ -3479,11 +3487,10 @@ def test_get_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.users_client, "get_bookmarks_by_folder_id")
+ method = getattr(self.users_client, "get_bookmark_folders")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -3518,7 +3525,7 @@ def test_get_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(
@@ -3534,12 +3541,12 @@ def test_get_bookmarks_by_folder_id_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_bookmarks_by_folder_id: {e}")
+ pytest.fail(f"Contract test failed for get_bookmark_folders: {e}")
- def test_get_bookmarks_by_folder_id_required_parameters(self):
- """Test that get_bookmarks_by_folder_id handles parameters correctly."""
- method = getattr(self.users_client, "get_bookmarks_by_folder_id")
+ def test_get_bookmark_folders_required_parameters(self):
+ """Test that get_bookmark_folders handles parameters correctly."""
+ method = getattr(self.users_client, "get_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)
@@ -3553,8 +3560,8 @@ def test_get_bookmarks_by_folder_id_required_parameters(self):
method()
- def test_get_bookmarks_by_folder_id_response_structure(self):
- """Test get_bookmarks_by_folder_id response structure validation."""
+ def test_get_bookmark_folders_response_structure(self):
+ """Test get_bookmark_folders response structure validation."""
with patch.object(self.client, "session") as mock_session:
# Create mock response with expected structure
mock_response_data = {
@@ -3568,10 +3575,9 @@ def test_get_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.users_client, "get_bookmarks_by_folder_id")
+ method = getattr(self.users_client, "get_bookmark_folders")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -3583,8 +3589,8 @@ def test_get_bookmarks_by_folder_id_response_structure(self):
)
- def test_like_post_request_structure(self):
- """Test like_post 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()
@@ -3593,19 +3599,15 @@ def test_like_post_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 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, "like_post")
+ method = getattr(self.users_client, "get_following")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -3624,7 +3626,7 @@ def test_like_post_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -3633,14 +3635,14 @@ def test_like_post_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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}/likes"
+ expected_path = "/2/users/{id}/following"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -3656,12 +3658,12 @@ def test_like_post_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for like_post: {e}")
+ pytest.fail(f"Contract test failed for get_following: {e}")
- def test_like_post_required_parameters(self):
- """Test that like_post handles parameters correctly."""
- method = getattr(self.users_client, "like_post")
+ 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)
@@ -3669,14 +3671,14 @@ def test_like_post_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_like_post_response_structure(self):
- """Test like_post 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 = {
@@ -3686,17 +3688,13 @@ def test_like_post_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 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, "like_post")
+ 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
@@ -3708,8 +3706,8 @@ def test_like_post_response_structure(self):
)
- def test_unpin_list_request_structure(self):
- """Test unpin_list 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()
@@ -3718,16 +3716,19 @@ def test_unpin_list_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"
- kwargs["list_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, "unpin_list")
+ method = getattr(self.users_client, "follow_user")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -3746,7 +3747,7 @@ def test_unpin_list_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.delete.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -3755,14 +3756,14 @@ def test_unpin_list_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/users/{id}/pinned_lists/{list_id}"
+ expected_path = "/2/users/{id}/following"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -3778,12 +3779,12 @@ def test_unpin_list_request_structure(self):
# For regular operations, verify we got a result
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 follow_user: {e}")
- def test_unpin_list_required_parameters(self):
- """Test that unpin_list handles parameters correctly."""
- method = getattr(self.users_client, "unpin_list")
+ 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)
@@ -3791,14 +3792,14 @@ def test_unpin_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.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_unpin_list_response_structure(self):
- """Test unpin_list 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 = {
@@ -3808,14 +3809,17 @@ def test_unpin_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.delete.return_value = mock_response
+ mock_session.post.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
kwargs["id"] = "test"
- kwargs["list_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, "unpin_list")
+ 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
@@ -3827,8 +3831,8 @@ def test_unpin_list_response_structure(self):
)
- def test_get_by_username_request_structure(self):
- """Test get_by_username request structure."""
+ 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()
@@ -3841,11 +3845,11 @@ def test_get_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_by_username")
+ method = getattr(self.users_client, "get_timeline")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -3880,7 +3884,7 @@ def test_get_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/users/{id}/timelines/reverse_chronological"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -3896,12 +3900,12 @@ def test_get_by_username_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_by_username: {e}")
+ pytest.fail(f"Contract test failed for get_timeline: {e}")
- def test_get_by_username_required_parameters(self):
- """Test that get_by_username handles parameters correctly."""
- method = getattr(self.users_client, "get_by_username")
+ 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)
@@ -3915,8 +3919,8 @@ def test_get_by_username_required_parameters(self):
method()
- def test_get_by_username_response_structure(self):
- """Test get_by_username response structure validation."""
+ 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 = {
@@ -3929,10 +3933,10 @@ def test_get_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_by_username")
+ 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
@@ -3944,8 +3948,8 @@ def test_get_by_username_response_structure(self):
)
- def test_delete_bookmark_request_structure(self):
- """Test delete_bookmark 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()
@@ -3954,16 +3958,15 @@ def test_delete_bookmark_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["tweet_id"] = "test_value"
+ kwargs["query"] = "test_value"
# Add request body if required
# Call the method
try:
- method = getattr(self.users_client, "delete_bookmark")
+ method = getattr(self.users_client, "search")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -3982,7 +3985,7 @@ def test_delete_bookmark_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.delete.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -3991,14 +3994,14 @@ def test_delete_bookmark_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/{id}/bookmarks/{tweet_id}"
+ expected_path = "/2/users/search"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -4014,12 +4017,12 @@ def test_delete_bookmark_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for delete_bookmark: {e}")
+ pytest.fail(f"Contract test failed for search: {e}")
- def test_delete_bookmark_required_parameters(self):
- """Test that delete_bookmark handles parameters correctly."""
- method = getattr(self.users_client, "delete_bookmark")
+ 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)
@@ -4027,14 +4030,14 @@ def test_delete_bookmark_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_delete_bookmark_response_structure(self):
- """Test delete_bookmark 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 = {
@@ -4044,14 +4047,13 @@ def test_delete_bookmark_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["tweet_id"] = "test"
+ kwargs["query"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.users_client, "delete_bookmark")
+ 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
@@ -4063,8 +4065,8 @@ def test_delete_bookmark_response_structure(self):
)
- def test_block_dms_request_structure(self):
- """Test block_dms 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()
@@ -4073,7 +4075,7 @@ def test_block_dms_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
@@ -4081,7 +4083,7 @@ def test_block_dms_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.users_client, "block_dms")
+ method = getattr(self.users_client, "get_bookmarks")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -4100,7 +4102,7 @@ def test_block_dms_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -4109,14 +4111,14 @@ def test_block_dms_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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}/dm/block"
+ expected_path = "/2/users/{id}/bookmarks"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -4132,12 +4134,12 @@ def test_block_dms_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for block_dms: {e}")
+ pytest.fail(f"Contract test failed for get_bookmarks: {e}")
- def test_block_dms_required_parameters(self):
- """Test that block_dms handles parameters correctly."""
- method = getattr(self.users_client, "block_dms")
+ 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)
@@ -4145,14 +4147,14 @@ def test_block_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.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_block_dms_response_structure(self):
- """Test block_dms 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 = {
@@ -4162,13 +4164,13 @@ def test_block_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.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, "block_dms")
+ 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
@@ -4180,8 +4182,8 @@ def test_block_dms_response_structure(self):
)
- def test_repost_post_request_structure(self):
- """Test repost_post request structure."""
+ def test_create_bookmark_request_structure(self):
+ """Test create_bookmark request structure."""
# Mock the session to capture request details
with patch.object(self.client, "session") as mock_session:
mock_response = Mock()
@@ -4197,12 +4199,12 @@ def test_repost_post_request_structure(self):
kwargs["id"] = "test_value"
# Add request body if required
# Import and create proper request model instance
- from xdk.users.models import RepostPostRequest
+ from xdk.users.models import CreateBookmarkRequest
# Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = RepostPostRequest()
+ kwargs["body"] = CreateBookmarkRequest()
# Call the method
try:
- method = getattr(self.users_client, "repost_post")
+ method = getattr(self.users_client, "create_bookmark")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -4237,7 +4239,7 @@ def test_repost_post_request_structure(self):
called_url = (
call_args[0][0] if call_args[0] else call_args[1].get("url", "")
)
- expected_path = "/2/users/{id}/retweets"
+ expected_path = "/2/users/{id}/bookmarks"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -4253,12 +4255,12 @@ def test_repost_post_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for repost_post: {e}")
+ pytest.fail(f"Contract test failed for create_bookmark: {e}")
- def test_repost_post_required_parameters(self):
- """Test that repost_post handles parameters correctly."""
- method = getattr(self.users_client, "repost_post")
+ def test_create_bookmark_required_parameters(self):
+ """Test that create_bookmark handles parameters correctly."""
+ method = getattr(self.users_client, "create_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)
@@ -4272,8 +4274,8 @@ def test_repost_post_required_parameters(self):
method()
- def test_repost_post_response_structure(self):
- """Test repost_post response structure validation."""
+ def test_create_bookmark_response_structure(self):
+ """Test create_bookmark response structure validation."""
with patch.object(self.client, "session") as mock_session:
# Create mock response with expected structure
mock_response_data = {
@@ -4289,11 +4291,11 @@ def test_repost_post_response_structure(self):
kwargs["id"] = "test"
# Add request body if required
# Import and create proper request model instance
- from xdk.users.models import RepostPostRequest
+ from xdk.users.models import CreateBookmarkRequest
# Create instance with minimal valid data (empty instance should work for most cases)
- kwargs["body"] = RepostPostRequest()
+ kwargs["body"] = CreateBookmarkRequest()
# Call method and verify response structure
- method = getattr(self.users_client, "repost_post")
+ method = getattr(self.users_client, "create_bookmark")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -4305,8 +4307,8 @@ def test_repost_post_response_structure(self):
)
- def test_unfollow_user_request_structure(self):
- """Test unfollow_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()
@@ -4315,16 +4317,14 @@ 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_reposts_of_me")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -4343,7 +4343,7 @@ def test_unfollow_user_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.delete.return_value = mock_streaming_response
+ mock_session.get.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -4352,14 +4352,14 @@ def test_unfollow_user_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/reposts_of_me"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -4375,27 +4375,27 @@ def test_unfollow_user_request_structure(self):
# For regular operations, verify we got a result
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_reposts_of_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_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 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_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 = {
@@ -4405,14 +4405,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_reposts_of_me")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -4424,8 +4422,8 @@ def test_unfollow_user_response_structure(self):
)
- def test_get_followers_request_structure(self):
- """Test get_followers 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()
@@ -4434,15 +4432,16 @@ def test_get_followers_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["list_id"] = "test_value"
# Add request body if required
# Call the method
try:
- method = getattr(self.users_client, "get_followers")
+ method = getattr(self.users_client, "unpin_list")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -4461,7 +4460,7 @@ def test_get_followers_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.get.return_value = mock_streaming_response
+ mock_session.delete.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -4470,14 +4469,14 @@ def test_get_followers_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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}/followers"
+ expected_path = "/2/users/{id}/pinned_lists/{list_id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -4493,12 +4492,12 @@ def test_get_followers_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for get_followers: {e}")
+ pytest.fail(f"Contract test failed for unpin_list: {e}")
- def test_get_followers_required_parameters(self):
- """Test that get_followers handles parameters correctly."""
- method = getattr(self.users_client, "get_followers")
+ def test_unpin_list_required_parameters(self):
+ """Test that unpin_list handles parameters correctly."""
+ method = getattr(self.users_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)
@@ -4506,14 +4505,14 @@ def test_get_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.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_followers_response_structure(self):
- """Test get_followers 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 = {
@@ -4523,13 +4522,14 @@ def test_get_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.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.users_client, "get_followers")
+ method = getattr(self.users_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/users/test_pagination.py b/xdk/python/tests/users/test_pagination.py
index dd982f9c..1c0936d4 100644
--- a/xdk/python/tests/users/test_pagination.py
+++ b/xdk/python/tests/users/test_pagination.py
@@ -169,20 +169,20 @@ def test_get_muting_pagination_parameters(self):
), "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")
+ 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_value", 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")
+ pytest.fail(f"Method get_list_memberships should support pagination")
- def test_get_posts_cursor_pages(self):
- """Test pagination with pages() for get_posts."""
+ 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()
@@ -203,7 +203,7 @@ def test_get_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.users_client, "get_posts")
+ method = getattr(self.users_client, "get_list_memberships")
test_cursor = cursor(method, "test_value", 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)}"
@@ -219,8 +219,8 @@ def test_get_posts_cursor_pages(self):
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."""
+ 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()
@@ -239,7 +239,7 @@ def test_get_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.users_client, "get_posts")
+ method = getattr(self.users_client, "get_list_memberships")
test_cursor = cursor(method, "test_value", 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)}"
@@ -250,15 +250,15 @@ def test_get_posts_cursor_items(self):
), "Items should have 'id' field"
- def test_get_posts_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_posts."""
+ 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_posts")
+ method = getattr(self.users_client, "get_list_memberships")
# Test with max_results parameter
test_cursor = cursor(method, "test_value", max_results=5)
list(test_cursor.pages(1)) # Trigger one request
@@ -311,20 +311,20 @@ def test_get_posts_pagination_parameters(self):
), "Pagination token should be passed correctly"
- def test_get_following_cursor_creation(self):
- """Test that get_following can be used with Cursor."""
- method = getattr(self.users_client, "get_following")
+ 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_value", max_results=10)
assert test_cursor is not None
assert isinstance(test_cursor, Cursor)
except PaginationError:
- pytest.fail(f"Method get_following should support pagination")
+ pytest.fail(f"Method get_liked_posts should support pagination")
- def test_get_following_cursor_pages(self):
- """Test pagination with pages() for get_following."""
+ 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()
@@ -345,7 +345,7 @@ def test_get_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_following")
+ method = getattr(self.users_client, "get_liked_posts")
test_cursor = cursor(method, "test_value", 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)}"
@@ -361,8 +361,8 @@ def test_get_following_cursor_pages(self):
assert len(second_data) == 1, "Second page should have 1 item"
- def test_get_following_cursor_items(self):
- """Test pagination with items() for get_following."""
+ 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()
@@ -381,7 +381,7 @@ def test_get_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_following")
+ method = getattr(self.users_client, "get_liked_posts")
test_cursor = cursor(method, "test_value", 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)}"
@@ -392,15 +392,15 @@ def test_get_following_cursor_items(self):
), "Items should have 'id' field"
- def test_get_following_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_following."""
+ 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_following")
+ method = getattr(self.users_client, "get_liked_posts")
# Test with max_results parameter
test_cursor = cursor(method, "test_value", max_results=5)
list(test_cursor.pages(1)) # Trigger one request
@@ -453,20 +453,20 @@ def test_get_following_pagination_parameters(self):
), "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")
+ 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_value", max_results=10)
assert test_cursor is not None
assert isinstance(test_cursor, Cursor)
except PaginationError:
- pytest.fail(f"Method get_timeline should support pagination")
+ pytest.fail(f"Method get_posts should support pagination")
- def test_get_timeline_cursor_pages(self):
- """Test pagination with pages() for get_timeline."""
+ 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()
@@ -487,7 +487,7 @@ def test_get_timeline_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_timeline")
+ method = getattr(self.users_client, "get_posts")
test_cursor = cursor(method, "test_value", 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)}"
@@ -503,8 +503,8 @@ def test_get_timeline_cursor_pages(self):
assert len(second_data) == 1, "Second page should have 1 item"
- def test_get_timeline_cursor_items(self):
- """Test pagination with items() for get_timeline."""
+ 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()
@@ -523,7 +523,7 @@ def test_get_timeline_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_timeline")
+ method = getattr(self.users_client, "get_posts")
test_cursor = cursor(method, "test_value", 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)}"
@@ -534,15 +534,15 @@ def test_get_timeline_cursor_items(self):
), "Items should have 'id' field"
- def test_get_timeline_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_timeline."""
+ 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_timeline")
+ method = getattr(self.users_client, "get_posts")
# Test with max_results parameter
test_cursor = cursor(method, "test_value", max_results=5)
list(test_cursor.pages(1)) # Trigger one request
@@ -595,20 +595,20 @@ def test_get_timeline_pagination_parameters(self):
), "Pagination token should be passed correctly"
- def test_search_cursor_creation(self):
- """Test that search can be used with Cursor."""
- method = getattr(self.users_client, "search")
+ 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_value", max_results=10)
assert test_cursor is not None
assert isinstance(test_cursor, Cursor)
except PaginationError:
- pytest.fail(f"Method search should support pagination")
+ pytest.fail(f"Method get_followed_lists should support pagination")
- def test_search_cursor_pages(self):
- """Test pagination with pages() for search."""
+ 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()
@@ -629,7 +629,7 @@ def test_search_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")
+ method = getattr(self.users_client, "get_followed_lists")
test_cursor = cursor(method, "test_value", 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)}"
@@ -645,8 +645,8 @@ def test_search_cursor_pages(self):
assert len(second_data) == 1, "Second page should have 1 item"
- def test_search_cursor_items(self):
- """Test pagination with items() for search."""
+ 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()
@@ -665,7 +665,7 @@ def test_search_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")
+ method = getattr(self.users_client, "get_followed_lists")
test_cursor = cursor(method, "test_value", 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)}"
@@ -676,15 +676,15 @@ def test_search_cursor_items(self):
), "Items should have 'id' field"
- def test_search_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for search."""
+ 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, "search")
+ method = getattr(self.users_client, "get_followed_lists")
# Test with max_results parameter
test_cursor = cursor(method, "test_value", max_results=5)
list(test_cursor.pages(1)) # Trigger one request
@@ -730,27 +730,27 @@ def test_search_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_owned_lists_cursor_creation(self):
- """Test that get_owned_lists can be used with Cursor."""
- method = getattr(self.users_client, "get_owned_lists")
+ 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_value", 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")
+ pytest.fail(f"Method get_mentions should support pagination")
- def test_get_owned_lists_cursor_pages(self):
- """Test pagination with pages() for get_owned_lists."""
+ 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()
@@ -771,7 +771,7 @@ def test_get_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.users_client, "get_owned_lists")
+ method = getattr(self.users_client, "get_mentions")
test_cursor = cursor(method, "test_value", 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)}"
@@ -787,8 +787,8 @@ def test_get_owned_lists_cursor_pages(self):
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."""
+ 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()
@@ -807,7 +807,7 @@ def test_get_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.users_client, "get_owned_lists")
+ method = getattr(self.users_client, "get_mentions")
test_cursor = cursor(method, "test_value", 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)}"
@@ -818,15 +818,15 @@ def test_get_owned_lists_cursor_items(self):
), "Items should have 'id' field"
- def test_get_owned_lists_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_owned_lists."""
+ 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_owned_lists")
+ method = getattr(self.users_client, "get_mentions")
# Test with max_results parameter
test_cursor = cursor(method, "test_value", max_results=5)
list(test_cursor.pages(1)) # Trigger one request
@@ -879,20 +879,20 @@ def test_get_owned_lists_pagination_parameters(self):
), "Pagination token should be passed correctly"
- def test_get_mentions_cursor_creation(self):
- """Test that get_mentions can be used with Cursor."""
- method = getattr(self.users_client, "get_mentions")
+ 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_value", max_results=10)
assert test_cursor is not None
assert isinstance(test_cursor, Cursor)
except PaginationError:
- pytest.fail(f"Method get_mentions should support pagination")
+ pytest.fail(f"Method get_owned_lists should support pagination")
- def test_get_mentions_cursor_pages(self):
- """Test pagination with pages() for get_mentions."""
+ 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()
@@ -913,7 +913,7 @@ def test_get_mentions_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_mentions")
+ method = getattr(self.users_client, "get_owned_lists")
test_cursor = cursor(method, "test_value", 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)}"
@@ -929,8 +929,8 @@ def test_get_mentions_cursor_pages(self):
assert len(second_data) == 1, "Second page should have 1 item"
- def test_get_mentions_cursor_items(self):
- """Test pagination with items() for get_mentions."""
+ 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()
@@ -949,7 +949,7 @@ def test_get_mentions_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_mentions")
+ method = getattr(self.users_client, "get_owned_lists")
test_cursor = cursor(method, "test_value", 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)}"
@@ -960,15 +960,15 @@ def test_get_mentions_cursor_items(self):
), "Items should have 'id' field"
- def test_get_mentions_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_mentions."""
+ 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_mentions")
+ method = getattr(self.users_client, "get_owned_lists")
# Test with max_results parameter
test_cursor = cursor(method, "test_value", max_results=5)
list(test_cursor.pages(1)) # Trigger one request
@@ -1021,20 +1021,20 @@ def test_get_mentions_pagination_parameters(self):
), "Pagination token should be passed correctly"
- 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")
+ 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_value", max_results=10)
assert test_cursor is not None
assert isinstance(test_cursor, Cursor)
except PaginationError:
- pytest.fail(f"Method get_list_memberships should support pagination")
+ pytest.fail(f"Method get_blocking should support pagination")
- def test_get_list_memberships_cursor_pages(self):
- """Test pagination with pages() for get_list_memberships."""
+ 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()
@@ -1055,7 +1055,7 @@ def test_get_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.users_client, "get_list_memberships")
+ method = getattr(self.users_client, "get_blocking")
test_cursor = cursor(method, "test_value", 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)}"
@@ -1071,8 +1071,8 @@ def test_get_list_memberships_cursor_pages(self):
assert len(second_data) == 1, "Second page should have 1 item"
- def test_get_list_memberships_cursor_items(self):
- """Test pagination with items() for get_list_memberships."""
+ 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()
@@ -1091,7 +1091,7 @@ def test_get_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.users_client, "get_list_memberships")
+ method = getattr(self.users_client, "get_blocking")
test_cursor = cursor(method, "test_value", 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)}"
@@ -1102,15 +1102,15 @@ def test_get_list_memberships_cursor_items(self):
), "Items should have 'id' field"
- def test_get_list_memberships_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_list_memberships."""
+ 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_list_memberships")
+ method = getattr(self.users_client, "get_blocking")
# Test with max_results parameter
test_cursor = cursor(method, "test_value", max_results=5)
list(test_cursor.pages(1)) # Trigger one request
@@ -1163,20 +1163,20 @@ def test_get_list_memberships_pagination_parameters(self):
), "Pagination token should be passed correctly"
- def test_get_blocking_cursor_creation(self):
- """Test that get_blocking can be used with Cursor."""
- method = getattr(self.users_client, "get_blocking")
+ 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_value", max_results=10)
assert test_cursor is not None
assert isinstance(test_cursor, Cursor)
except PaginationError:
- pytest.fail(f"Method get_blocking should support pagination")
+ pytest.fail(f"Method get_followers should support pagination")
- def test_get_blocking_cursor_pages(self):
- """Test pagination with pages() for get_blocking."""
+ 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()
@@ -1197,7 +1197,7 @@ def test_get_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_blocking")
+ method = getattr(self.users_client, "get_followers")
test_cursor = cursor(method, "test_value", 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)}"
@@ -1213,8 +1213,8 @@ def test_get_blocking_cursor_pages(self):
assert len(second_data) == 1, "Second page should have 1 item"
- def test_get_blocking_cursor_items(self):
- """Test pagination with items() for get_blocking."""
+ 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()
@@ -1233,7 +1233,7 @@ def test_get_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_blocking")
+ method = getattr(self.users_client, "get_followers")
test_cursor = cursor(method, "test_value", 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)}"
@@ -1244,15 +1244,15 @@ def test_get_blocking_cursor_items(self):
), "Items should have 'id' field"
- def test_get_blocking_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_blocking."""
+ 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_blocking")
+ method = getattr(self.users_client, "get_followers")
# Test with max_results parameter
test_cursor = cursor(method, "test_value", max_results=5)
list(test_cursor.pages(1)) # Trigger one request
@@ -1305,20 +1305,20 @@ def test_get_blocking_pagination_parameters(self):
), "Pagination token should be passed correctly"
- 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")
+ def test_get_bookmark_folders_cursor_creation(self):
+ """Test that get_bookmark_folders can be used with Cursor."""
+ method = getattr(self.users_client, "get_bookmark_folders")
# Should be able to create cursor without error
try:
test_cursor = cursor(method, "test_value", max_results=10)
assert test_cursor is not None
assert isinstance(test_cursor, Cursor)
except PaginationError:
- pytest.fail(f"Method get_followed_lists should support pagination")
+ pytest.fail(f"Method get_bookmark_folders should support pagination")
- def test_get_followed_lists_cursor_pages(self):
- """Test pagination with pages() for get_followed_lists."""
+ def test_get_bookmark_folders_cursor_pages(self):
+ """Test pagination with pages() for get_bookmark_folders."""
with patch.object(self.client, "session") as mock_session:
# Mock first page response
first_page_response = Mock()
@@ -1339,7 +1339,7 @@ def test_get_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.users_client, "get_followed_lists")
+ method = getattr(self.users_client, "get_bookmark_folders")
test_cursor = cursor(method, "test_value", 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)}"
@@ -1355,8 +1355,8 @@ def test_get_followed_lists_cursor_pages(self):
assert len(second_data) == 1, "Second page should have 1 item"
- def test_get_followed_lists_cursor_items(self):
- """Test pagination with items() for get_followed_lists."""
+ def test_get_bookmark_folders_cursor_items(self):
+ """Test pagination with items() for get_bookmark_folders."""
with patch.object(self.client, "session") as mock_session:
# Mock response with paginated data
mock_response = Mock()
@@ -1375,7 +1375,7 @@ def test_get_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.users_client, "get_followed_lists")
+ method = getattr(self.users_client, "get_bookmark_folders")
test_cursor = cursor(method, "test_value", 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)}"
@@ -1386,15 +1386,15 @@ def test_get_followed_lists_cursor_items(self):
), "Items should have 'id' field"
- def test_get_followed_lists_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_followed_lists."""
+ def test_get_bookmark_folders_pagination_parameters(self):
+ """Test that pagination parameters are handled correctly for get_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": [], "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_followed_lists")
+ method = getattr(self.users_client, "get_bookmark_folders")
# Test with max_results parameter
test_cursor = cursor(method, "test_value", max_results=5)
list(test_cursor.pages(1)) # Trigger one request
@@ -1447,20 +1447,20 @@ def test_get_followed_lists_pagination_parameters(self):
), "Pagination token should be passed correctly"
- 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")
+ 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, max_results=10)
+ test_cursor = cursor(method, "test_value", max_results=10)
assert test_cursor is not None
assert isinstance(test_cursor, Cursor)
except PaginationError:
- pytest.fail(f"Method get_reposts_of_me should support pagination")
+ pytest.fail(f"Method get_following should support pagination")
- def test_get_reposts_of_me_cursor_pages(self):
- """Test pagination with pages() for get_reposts_of_me."""
+ 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()
@@ -1481,8 +1481,8 @@ def test_get_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_reposts_of_me")
- test_cursor = cursor(method, max_results=2)
+ method = getattr(self.users_client, "get_following")
+ test_cursor = cursor(method, "test_value", 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
@@ -1497,8 +1497,8 @@ def test_get_reposts_of_me_cursor_pages(self):
assert len(second_data) == 1, "Second page should have 1 item"
- def test_get_reposts_of_me_cursor_items(self):
- """Test pagination with items() for get_reposts_of_me."""
+ 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()
@@ -1517,8 +1517,8 @@ def test_get_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_reposts_of_me")
- test_cursor = cursor(method, max_results=10)
+ method = getattr(self.users_client, "get_following")
+ test_cursor = cursor(method, "test_value", 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
@@ -1528,17 +1528,17 @@ def test_get_reposts_of_me_cursor_items(self):
), "Items should have 'id' field"
- def test_get_reposts_of_me_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_reposts_of_me."""
+ 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_reposts_of_me")
+ method = getattr(self.users_client, "get_following")
# Test with max_results parameter
- test_cursor = cursor(method, max_results=5)
+ test_cursor = cursor(method, "test_value", 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
@@ -1567,7 +1567,7 @@ def test_get_reposts_of_me_pagination_parameters(self):
mock_response_with_token,
second_page_response,
]
- test_cursor = cursor(method, max_results=1)
+ test_cursor = cursor(method, "test_value", max_results=1)
pages = list(test_cursor.pages(2))
# Should have made 2 requests
assert (
@@ -1589,20 +1589,20 @@ def test_get_reposts_of_me_pagination_parameters(self):
), "Pagination token should be passed correctly"
- def test_get_bookmarks_cursor_creation(self):
- """Test that get_bookmarks can be used with Cursor."""
- method = getattr(self.users_client, "get_bookmarks")
+ 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_value", max_results=10)
assert test_cursor is not None
assert isinstance(test_cursor, Cursor)
except PaginationError:
- pytest.fail(f"Method get_bookmarks should support pagination")
+ pytest.fail(f"Method get_timeline should support pagination")
- def test_get_bookmarks_cursor_pages(self):
- """Test pagination with pages() for get_bookmarks."""
+ 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()
@@ -1623,7 +1623,7 @@ def test_get_bookmarks_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_bookmarks")
+ method = getattr(self.users_client, "get_timeline")
test_cursor = cursor(method, "test_value", 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)}"
@@ -1639,8 +1639,8 @@ def test_get_bookmarks_cursor_pages(self):
assert len(second_data) == 1, "Second page should have 1 item"
- def test_get_bookmarks_cursor_items(self):
- """Test pagination with items() for get_bookmarks."""
+ 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()
@@ -1659,7 +1659,7 @@ def test_get_bookmarks_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_bookmarks")
+ method = getattr(self.users_client, "get_timeline")
test_cursor = cursor(method, "test_value", 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)}"
@@ -1670,15 +1670,15 @@ def test_get_bookmarks_cursor_items(self):
), "Items should have 'id' field"
- def test_get_bookmarks_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_bookmarks."""
+ 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, "get_bookmarks")
+ method = getattr(self.users_client, "get_timeline")
# Test with max_results parameter
test_cursor = cursor(method, "test_value", max_results=5)
list(test_cursor.pages(1)) # Trigger one request
@@ -1731,20 +1731,20 @@ def test_get_bookmarks_pagination_parameters(self):
), "Pagination token should be passed correctly"
- def test_get_bookmark_folders_cursor_creation(self):
- """Test that get_bookmark_folders can be used with Cursor."""
- method = getattr(self.users_client, "get_bookmark_folders")
+ 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_value", max_results=10)
assert test_cursor is not None
assert isinstance(test_cursor, Cursor)
except PaginationError:
- pytest.fail(f"Method get_bookmark_folders should support pagination")
+ pytest.fail(f"Method search should support pagination")
- def test_get_bookmark_folders_cursor_pages(self):
- """Test pagination with pages() for get_bookmark_folders."""
+ 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()
@@ -1765,7 +1765,7 @@ def test_get_bookmark_folders_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_bookmark_folders")
+ method = getattr(self.users_client, "search")
test_cursor = cursor(method, "test_value", 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)}"
@@ -1781,8 +1781,8 @@ def test_get_bookmark_folders_cursor_pages(self):
assert len(second_data) == 1, "Second page should have 1 item"
- def test_get_bookmark_folders_cursor_items(self):
- """Test pagination with items() for get_bookmark_folders."""
+ 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()
@@ -1801,7 +1801,7 @@ def test_get_bookmark_folders_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_bookmark_folders")
+ method = getattr(self.users_client, "search")
test_cursor = cursor(method, "test_value", 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)}"
@@ -1812,15 +1812,15 @@ def test_get_bookmark_folders_cursor_items(self):
), "Items should have 'id' field"
- def test_get_bookmark_folders_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_bookmark_folders."""
+ 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, "get_bookmark_folders")
+ method = getattr(self.users_client, "search")
# Test with max_results parameter
test_cursor = cursor(method, "test_value", max_results=5)
list(test_cursor.pages(1)) # Trigger one request
@@ -1866,27 +1866,27 @@ def test_get_bookmark_folders_pagination_parameters(self):
):
second_params = second_call_args[1]["params"]
assert (
- "pagination_token" in second_params
- ), "Second request should include pagination_token"
+ "next_token" in second_params
+ ), "Second request should include next_token"
assert (
- second_params["pagination_token"] == "next_token_value"
+ second_params["next_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")
+ 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_value", 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")
+ pytest.fail(f"Method get_bookmarks should support pagination")
- def test_get_liked_posts_cursor_pages(self):
- """Test pagination with pages() for get_liked_posts."""
+ 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()
@@ -1907,7 +1907,7 @@ def test_get_liked_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.users_client, "get_liked_posts")
+ method = getattr(self.users_client, "get_bookmarks")
test_cursor = cursor(method, "test_value", 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)}"
@@ -1923,8 +1923,8 @@ def test_get_liked_posts_cursor_pages(self):
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."""
+ 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()
@@ -1943,7 +1943,7 @@ def test_get_liked_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.users_client, "get_liked_posts")
+ method = getattr(self.users_client, "get_bookmarks")
test_cursor = cursor(method, "test_value", 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)}"
@@ -1954,15 +1954,15 @@ def test_get_liked_posts_cursor_items(self):
), "Items should have 'id' field"
- def test_get_liked_posts_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_liked_posts."""
+ 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_liked_posts")
+ method = getattr(self.users_client, "get_bookmarks")
# Test with max_results parameter
test_cursor = cursor(method, "test_value", max_results=5)
list(test_cursor.pages(1)) # Trigger one request
@@ -2015,20 +2015,20 @@ def test_get_liked_posts_pagination_parameters(self):
), "Pagination token should be passed correctly"
- def test_get_followers_cursor_creation(self):
- """Test that get_followers can be used with Cursor."""
- method = getattr(self.users_client, "get_followers")
+ 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, "test_value", max_results=10)
+ test_cursor = cursor(method, max_results=10)
assert test_cursor is not None
assert isinstance(test_cursor, Cursor)
except PaginationError:
- pytest.fail(f"Method get_followers should support pagination")
+ pytest.fail(f"Method get_reposts_of_me should support pagination")
- def test_get_followers_cursor_pages(self):
- """Test pagination with pages() for get_followers."""
+ 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()
@@ -2049,8 +2049,8 @@ def test_get_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_followers")
- test_cursor = cursor(method, "test_value", max_results=2)
+ 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)}"
# Verify first page
@@ -2065,8 +2065,8 @@ def test_get_followers_cursor_pages(self):
assert len(second_data) == 1, "Second page should have 1 item"
- def test_get_followers_cursor_items(self):
- """Test pagination with items() for get_followers."""
+ 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()
@@ -2085,8 +2085,8 @@ def test_get_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_followers")
- test_cursor = cursor(method, "test_value", max_results=10)
+ 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)}"
# Verify items have expected structure
@@ -2096,17 +2096,17 @@ def test_get_followers_cursor_items(self):
), "Items should have 'id' field"
- def test_get_followers_pagination_parameters(self):
- """Test that pagination parameters are handled correctly for get_followers."""
+ 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_followers")
+ method = getattr(self.users_client, "get_reposts_of_me")
# Test with max_results parameter
- test_cursor = cursor(method, "test_value", max_results=5)
+ 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
@@ -2135,7 +2135,7 @@ def test_get_followers_pagination_parameters(self):
mock_response_with_token,
second_page_response,
]
- test_cursor = cursor(method, "test_value", max_results=1)
+ test_cursor = cursor(method, max_results=1)
pages = list(test_cursor.pages(2))
# Should have made 2 requests
assert (
diff --git a/xdk/python/tests/users/test_structure.py b/xdk/python/tests/users/test_structure.py
index 7eeef541..0b69572c 100644
--- a/xdk/python/tests/users/test_structure.py
+++ b/xdk/python/tests/users/test_structure.py
@@ -28,33 +28,31 @@ def setup_class(self):
self.users_client = getattr(self.client, "users")
- def test_get_me_exists(self):
- """Test that get_me 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_me", None)
- assert method is not None, f"Method get_me does not exist on UsersClient"
+ method = getattr(UsersClient, "like_post", None)
+ assert method is not None, f"Method like_post does not exist on UsersClient"
# Check method is callable
- assert callable(method), f"get_me 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_me 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]}'"
# 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_me"
+ ), f"Required parameter '{required_param}' missing from like_post"
# Check optional parameters have defaults (excluding 'self')
- optional_params = [
- "user.fields",
- "expansions",
- "tweet.fields",
- ]
+ optional_params = []
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -63,40 +61,40 @@ def test_get_me_exists(self):
), 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")
+ def test_like_post_return_annotation(self):
+ """Test that like_post has proper return type annotation."""
+ method = getattr(UsersClient, "like_post")
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"
+ ), f"Method like_post should have return type annotation"
- def test_unfollow_list_exists(self):
- """Test that unfollow_list 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, "unfollow_list", None)
- assert method is not None, f"Method unfollow_list does not exist on UsersClient"
+ method = getattr(UsersClient, "unlike_post", None)
+ assert method is not None, f"Method unlike_post does not exist on UsersClient"
# Check method is callable
- assert callable(method), f"unfollow_list 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"unfollow_list 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",
- "list_id",
+ "tweet_id",
]
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 unlike_post"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -107,14 +105,14 @@ 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(UsersClient, "unfollow_list")
+ def test_unlike_post_return_annotation(self):
+ """Test that unlike_post has proper return type annotation."""
+ method = getattr(UsersClient, "unlike_post")
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 unlike_post should have return type annotation"
def test_get_muting_exists(self):
@@ -228,32 +226,39 @@ def test_mute_user_return_annotation(self):
), f"Method mute_user should have return type annotation"
- def test_unlike_post_exists(self):
- """Test that unlike_post method exists with correct signature."""
+ def test_get_pinned_lists_exists(self):
+ """Test that get_pinned_lists method exists with correct signature."""
# Check method exists
- method = getattr(UsersClient, "unlike_post", None)
- assert method is not None, f"Method unlike_post does not exist on UsersClient"
+ method = getattr(UsersClient, "get_pinned_lists", None)
+ assert (
+ method is not None
+ ), f"Method get_pinned_lists does not exist on UsersClient"
# Check method is callable
- assert callable(method), f"unlike_post is not callable"
+ assert callable(method), f"get_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"unlike_post should have at least 'self' parameter"
+ assert (
+ len(params) >= 1
+ ), f"get_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",
- "tweet_id",
]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from unlike_post"
+ ), f"Required parameter '{required_param}' missing from get_pinned_lists"
# Check optional parameters have defaults (excluding 'self')
- optional_params = []
+ optional_params = [
+ "list.fields",
+ "expansions",
+ "user.fields",
+ ]
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -262,28 +267,28 @@ def test_unlike_post_exists(self):
), 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(UsersClient, "unlike_post")
+ def test_get_pinned_lists_return_annotation(self):
+ """Test that get_pinned_lists has proper return type annotation."""
+ method = getattr(UsersClient, "get_pinned_lists")
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"
+ ), f"Method get_pinned_lists should have return type annotation"
- def test_get_posts_exists(self):
- """Test that get_posts 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(UsersClient, "get_posts", None)
- assert method is not None, f"Method get_posts does not exist on UsersClient"
+ method = getattr(UsersClient, "pin_list", None)
+ assert method is not None, f"Method pin_list does not exist on UsersClient"
# Check method is callable
- assert callable(method), f"get_posts 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_posts 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]}'"
@@ -294,23 +299,9 @@ def test_get_posts_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_posts"
+ ), f"Required parameter '{required_param}' missing from pin_list"
# Check optional parameters have defaults (excluding 'self')
- optional_params = [
- "since_id",
- "until_id",
- "max_results",
- "pagination_token",
- "exclude",
- "start_time",
- "end_time",
- "tweet.fields",
- "expansions",
- "media.fields",
- "poll.fields",
- "user.fields",
- "place.fields",
- ]
+ optional_params = []
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -319,66 +310,42 @@ def test_get_posts_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_posts_return_annotation(self):
- """Test that get_posts has proper return type annotation."""
- method = getattr(UsersClient, "get_posts")
+ def test_pin_list_return_annotation(self):
+ """Test that pin_list has proper return type annotation."""
+ method = getattr(UsersClient, "pin_list")
sig = inspect.signature(method)
# Check return annotation exists
assert (
sig.return_annotation is not inspect.Signature.empty
- ), f"Method get_posts should have return type annotation"
-
-
- 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
- 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"
+ ), f"Method pin_list should have return type annotation"
- def test_get_following_exists(self):
- """Test that get_following 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_following", None)
- assert method is not None, f"Method get_following does not exist on UsersClient"
+ method = getattr(UsersClient, "unrepost_post", None)
+ assert method is not None, f"Method unrepost_post does not exist on UsersClient"
# Check method is callable
- assert callable(method), f"get_following 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_following 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_following"
+ ), f"Required parameter '{required_param}' missing from unrepost_post"
# Check optional parameters have defaults (excluding 'self')
- optional_params = [
- "max_results",
- "pagination_token",
- "user.fields",
- "expansions",
- "tweet.fields",
- ]
+ optional_params = []
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -387,58 +354,40 @@ def test_get_following_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_following_return_annotation(self):
- """Test that get_following has proper return type annotation."""
- method = getattr(UsersClient, "get_following")
+ def test_unrepost_post_return_annotation(self):
+ """Test that unrepost_post has proper return type annotation."""
+ method = getattr(UsersClient, "unrepost_post")
sig = inspect.signature(method)
# Check return annotation exists
assert (
sig.return_annotation is not inspect.Signature.empty
- ), f"Method get_following should have return type annotation"
-
-
- 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
- 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_following should have pagination parameters"
+ ), f"Method unrepost_post should have return type annotation"
- def test_follow_user_exists(self):
- """Test that follow_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, "follow_user", None)
- assert method is not None, f"Method follow_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"follow_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"follow_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]}'"
# Check required parameters exist (excluding 'self')
required_params = [
- "id",
+ "source_user_id",
+ "target_user_id",
]
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 unmute_user"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -449,55 +398,46 @@ 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_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 follow_user should have return type annotation"
+ ), f"Method unmute_user should have return type annotation"
- def test_get_timeline_exists(self):
- """Test that get_timeline method exists with correct signature."""
+ def test_delete_bookmark_exists(self):
+ """Test that delete_bookmark 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"
+ method = getattr(UsersClient, "delete_bookmark", None)
+ assert (
+ method is not None
+ ), f"Method delete_bookmark does not exist on UsersClient"
# Check method is callable
- assert callable(method), f"get_timeline is not callable"
+ assert callable(method), f"delete_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"get_timeline should have at least 'self' parameter"
+ assert (
+ len(params) >= 1
+ ), f"delete_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 get_timeline"
+ ), f"Required parameter '{required_param}' missing from delete_bookmark"
# Check optional parameters have defaults (excluding 'self')
- optional_params = [
- "since_id",
- "until_id",
- "max_results",
- "pagination_token",
- "exclude",
- "start_time",
- "end_time",
- "tweet.fields",
- "expansions",
- "media.fields",
- "poll.fields",
- "user.fields",
- "place.fields",
- ]
+ optional_params = []
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -506,19 +446,72 @@ def test_get_timeline_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_timeline_return_annotation(self):
- """Test that get_timeline has proper return type annotation."""
- method = getattr(UsersClient, "get_timeline")
+ def test_delete_bookmark_return_annotation(self):
+ """Test that delete_bookmark has proper return type annotation."""
+ method = getattr(UsersClient, "delete_bookmark")
sig = inspect.signature(method)
# Check return annotation exists
assert (
sig.return_annotation is not inspect.Signature.empty
- ), f"Method get_timeline should have return type annotation"
+ ), f"Method delete_bookmark should have return type annotation"
- def test_get_timeline_pagination_params(self):
- """Test that get_timeline has pagination parameters."""
- method = getattr(UsersClient, "get_timeline")
+ def test_get_list_memberships_exists(self):
+ """Test that get_list_memberships method exists with correct signature."""
+ # Check method exists
+ method = getattr(UsersClient, "get_list_memberships", None)
+ assert (
+ method is not None
+ ), f"Method get_list_memberships does not exist on UsersClient"
+ # Check method is 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_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_list_memberships"
+ # Check optional parameters have defaults (excluding 'self')
+ optional_params = [
+ "max_results",
+ "pagination_token",
+ "list.fields",
+ "expansions",
+ "user.fields",
+ ]
+ 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_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_list_memberships should have return type annotation"
+
+
+ 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
@@ -532,35 +525,36 @@ def test_get_timeline_pagination_params(self):
has_pagination_param = any(param in params for param in pagination_params)
assert (
has_pagination_param
- ), f"Paginated method get_timeline should have pagination parameters"
+ ), f"Paginated method get_list_memberships should have pagination parameters"
- def test_unmute_user_exists(self):
- """Test that unmute_user 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, "unmute_user", None)
- assert method is not None, f"Method unmute_user 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"unmute_user 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"unmute_user should have at least 'self' parameter"
+ assert len(params) >= 1, f"get_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 = [
- "source_user_id",
- "target_user_id",
- ]
+ required_params = []
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 get_me"
# Check optional parameters have defaults (excluding 'self')
- optional_params = []
+ optional_params = [
+ "user.fields",
+ "expansions",
+ "tweet.fields",
+ ]
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -569,46 +563,53 @@ 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_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 unmute_user should have return type annotation"
+ ), f"Method get_me should have return type annotation"
- def test_search_exists(self):
- """Test that search 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, "search", None)
- assert method is not None, f"Method search does not exist on UsersClient"
+ method = getattr(UsersClient, "get_liked_posts", None)
+ assert (
+ method is not None
+ ), f"Method get_liked_posts does not exist on UsersClient"
# Check method is callable
- assert callable(method), f"search 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"search should have at least 'self' parameter"
+ assert (
+ len(params) >= 1
+ ), 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 = [
- "query",
+ "id",
]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from search"
+ ), f"Required parameter '{required_param}' missing from get_liked_posts"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
"max_results",
- "next_token",
- "user.fields",
- "expansions",
+ "pagination_token",
"tweet.fields",
+ "expansions",
+ "media.fields",
+ "poll.fields",
+ "user.fields",
+ "place.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -618,19 +619,19 @@ def test_search_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_search_return_annotation(self):
- """Test that search has proper return type annotation."""
- method = getattr(UsersClient, "search")
+ 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 search should have return type annotation"
+ ), f"Method get_liked_posts should have return type annotation"
- def test_search_pagination_params(self):
- """Test that search has pagination parameters."""
- method = getattr(UsersClient, "search")
+ 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
@@ -644,25 +645,21 @@ def test_search_pagination_params(self):
has_pagination_param = any(param in params for param in pagination_params)
assert (
has_pagination_param
- ), f"Paginated method search should have pagination parameters"
+ ), f"Paginated method get_liked_posts should have pagination parameters"
- def test_get_owned_lists_exists(self):
- """Test that get_owned_lists 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, "get_owned_lists", None)
- assert (
- method is not None
- ), f"Method get_owned_lists 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"get_owned_lists 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_owned_lists 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]}'"
@@ -673,14 +670,22 @@ def test_get_owned_lists_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_owned_lists"
+ ), f"Required parameter '{required_param}' missing from get_posts"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
+ "since_id",
+ "until_id",
"max_results",
"pagination_token",
- "list.fields",
+ "exclude",
+ "start_time",
+ "end_time",
+ "tweet.fields",
"expansions",
+ "media.fields",
+ "poll.fields",
"user.fields",
+ "place.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -690,19 +695,19 @@ def test_get_owned_lists_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_owned_lists_return_annotation(self):
- """Test that get_owned_lists has proper return type annotation."""
- method = getattr(UsersClient, "get_owned_lists")
+ 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 get_owned_lists should have return type annotation"
+ ), f"Method get_posts should have return type annotation"
- def test_get_owned_lists_pagination_params(self):
- """Test that get_owned_lists has pagination parameters."""
- method = getattr(UsersClient, "get_owned_lists")
+ 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
@@ -716,41 +721,43 @@ def test_get_owned_lists_pagination_params(self):
has_pagination_param = any(param in params for param in pagination_params)
assert (
has_pagination_param
- ), f"Paginated method get_owned_lists should have pagination parameters"
+ ), f"Paginated method get_posts should have pagination parameters"
- def test_get_by_usernames_exists(self):
- """Test that get_by_usernames 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_by_usernames", None)
+ method = getattr(UsersClient, "get_followed_lists", None)
assert (
method is not None
- ), f"Method get_by_usernames does not exist on UsersClient"
+ ), f"Method get_followed_lists does not exist on UsersClient"
# Check method is callable
- assert callable(method), f"get_by_usernames 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_by_usernames 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]}'"
# 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_by_usernames"
+ ), f"Required parameter '{required_param}' missing from get_followed_lists"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "user.fields",
+ "max_results",
+ "pagination_token",
+ "list.fields",
"expansions",
- "tweet.fields",
+ "user.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -760,28 +767,47 @@ def test_get_by_usernames_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_by_usernames_return_annotation(self):
- """Test that get_by_usernames has proper return type annotation."""
- method = getattr(UsersClient, "get_by_usernames")
+ 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_by_usernames should have return type annotation"
+ ), f"Method get_followed_lists should have return type annotation"
- def test_get_mentions_exists(self):
- """Test that get_mentions method exists with correct signature."""
+ 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
+ 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_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(UsersClient, "get_mentions", None)
- assert method is not None, f"Method get_mentions does not exist on UsersClient"
+ method = getattr(UsersClient, "follow_list", None)
+ assert method is not None, f"Method follow_list does not exist on UsersClient"
# Check method is callable
- assert callable(method), f"get_mentions 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_mentions 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]}'"
@@ -792,22 +818,9 @@ def test_get_mentions_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_mentions"
+ ), f"Required parameter '{required_param}' missing from follow_list"
# Check optional parameters have defaults (excluding 'self')
- optional_params = [
- "since_id",
- "until_id",
- "max_results",
- "pagination_token",
- "start_time",
- "end_time",
- "tweet.fields",
- "expansions",
- "media.fields",
- "poll.fields",
- "user.fields",
- "place.fields",
- ]
+ optional_params = []
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -816,69 +829,48 @@ def test_get_mentions_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_mentions_return_annotation(self):
- """Test that get_mentions has proper return type annotation."""
- method = getattr(UsersClient, "get_mentions")
+ def test_follow_list_return_annotation(self):
+ """Test that follow_list has proper return type annotation."""
+ method = getattr(UsersClient, "follow_list")
sig = inspect.signature(method)
# Check return annotation exists
assert (
sig.return_annotation is not inspect.Signature.empty
- ), f"Method get_mentions should have return type annotation"
-
-
- 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 (
- has_pagination_param
- ), f"Paginated method get_mentions should have pagination parameters"
+ ), f"Method follow_list should have return type annotation"
- def test_get_list_memberships_exists(self):
- """Test that get_list_memberships method exists with correct signature."""
+ def test_get_by_username_exists(self):
+ """Test that get_by_username method exists with correct signature."""
# Check method exists
- method = getattr(UsersClient, "get_list_memberships", None)
+ method = getattr(UsersClient, "get_by_username", None)
assert (
method is not None
- ), f"Method get_list_memberships does not exist on UsersClient"
+ ), f"Method get_by_username does not exist on UsersClient"
# Check method is callable
- assert callable(method), f"get_list_memberships is not 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_list_memberships should have at least 'self' parameter"
+ ), 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 = [
- "id",
+ "username",
]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_list_memberships"
+ ), f"Required parameter '{required_param}' missing from get_by_username"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "max_results",
- "pagination_token",
- "list.fields",
- "expansions",
"user.fields",
+ "expansions",
+ "tweet.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -888,47 +880,28 @@ def test_get_list_memberships_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_list_memberships_return_annotation(self):
- """Test that get_list_memberships has proper return type annotation."""
- method = getattr(UsersClient, "get_list_memberships")
+ 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_list_memberships should have return type annotation"
-
-
- 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
- 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_list_memberships should have pagination parameters"
+ ), f"Method get_by_username should have return type annotation"
- def test_get_blocking_exists(self):
- """Test that get_blocking 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_blocking", None)
- assert method is not None, f"Method get_blocking 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_blocking 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_blocking 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]}'"
@@ -939,14 +912,21 @@ def test_get_blocking_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_blocking"
+ ), f"Required parameter '{required_param}' missing from get_mentions"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
+ "since_id",
+ "until_id",
"max_results",
"pagination_token",
- "user.fields",
- "expansions",
+ "start_time",
+ "end_time",
"tweet.fields",
+ "expansions",
+ "media.fields",
+ "poll.fields",
+ "user.fields",
+ "place.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -956,19 +936,19 @@ def test_get_blocking_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_blocking_return_annotation(self):
- """Test that get_blocking has proper return type annotation."""
- method = getattr(UsersClient, "get_blocking")
+ 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_blocking should have return type annotation"
+ ), f"Method get_mentions should have return type annotation"
- def test_get_blocking_pagination_params(self):
- """Test that get_blocking has pagination parameters."""
- method = getattr(UsersClient, "get_blocking")
+ 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
@@ -982,25 +962,25 @@ def test_get_blocking_pagination_params(self):
has_pagination_param = any(param in params for param in pagination_params)
assert (
has_pagination_param
- ), f"Paginated method get_blocking should have pagination parameters"
+ ), f"Paginated method get_mentions should have pagination parameters"
- def test_get_followed_lists_exists(self):
- """Test that get_followed_lists 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_followed_lists", None)
+ method = getattr(UsersClient, "get_owned_lists", None)
assert (
method is not None
- ), f"Method get_followed_lists does not exist on UsersClient"
+ ), f"Method get_owned_lists does not exist on UsersClient"
# Check method is callable
- assert callable(method), f"get_followed_lists 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_followed_lists 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]}'"
@@ -1011,7 +991,7 @@ def test_get_followed_lists_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_followed_lists"
+ ), f"Required parameter '{required_param}' missing from get_owned_lists"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
"max_results",
@@ -1028,19 +1008,19 @@ def test_get_followed_lists_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_followed_lists_return_annotation(self):
- """Test that get_followed_lists has proper return type annotation."""
- method = getattr(UsersClient, "get_followed_lists")
+ 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_followed_lists should have return type annotation"
+ ), f"Method get_owned_lists should have return type annotation"
- def test_get_followed_lists_pagination_params(self):
- """Test that get_followed_lists has pagination parameters."""
- method = getattr(UsersClient, "get_followed_lists")
+ 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
@@ -1054,21 +1034,21 @@ def test_get_followed_lists_pagination_params(self):
has_pagination_param = any(param in params for param in pagination_params)
assert (
has_pagination_param
- ), f"Paginated method get_followed_lists should have pagination parameters"
+ ), f"Paginated method get_owned_lists should have pagination parameters"
- def test_follow_list_exists(self):
- """Test that follow_list 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, "follow_list", None)
- assert method is not None, f"Method follow_list does not exist on UsersClient"
+ method = getattr(UsersClient, "repost_post", None)
+ assert method is not None, f"Method repost_post does not exist on UsersClient"
# Check method is callable
- assert callable(method), f"follow_list 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"follow_list 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]}'"
@@ -1079,7 +1059,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 repost_post"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -1090,40 +1070,40 @@ 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(UsersClient, "follow_list")
+ def test_repost_post_return_annotation(self):
+ """Test that repost_post has proper return type annotation."""
+ method = getattr(UsersClient, "repost_post")
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 repost_post should have return type annotation"
- def test_unrepost_post_exists(self):
- """Test that unrepost_post method exists with correct signature."""
+ def test_unfollow_list_exists(self):
+ """Test that unfollow_list method exists with correct signature."""
# Check method exists
- method = getattr(UsersClient, "unrepost_post", None)
- assert method is not None, f"Method unrepost_post does not exist on UsersClient"
+ method = getattr(UsersClient, "unfollow_list", None)
+ assert method is not None, f"Method unfollow_list does not exist on UsersClient"
# Check method is callable
- assert callable(method), f"unrepost_post 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"unrepost_post 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]}'"
# Check required parameters exist (excluding 'self')
required_params = [
"id",
- "source_tweet_id",
+ "list_id",
]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from unrepost_post"
+ ), f"Required parameter '{required_param}' missing from unfollow_list"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -1134,51 +1114,44 @@ def test_unrepost_post_exists(self):
), 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(UsersClient, "unrepost_post")
+ def test_unfollow_list_return_annotation(self):
+ """Test that unfollow_list has proper return type annotation."""
+ method = getattr(UsersClient, "unfollow_list")
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"
+ ), f"Method unfollow_list should have return type annotation"
- def test_get_reposts_of_me_exists(self):
- """Test that get_reposts_of_me 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_reposts_of_me", None)
- assert (
- method is not None
- ), f"Method get_reposts_of_me 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_reposts_of_me 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_reposts_of_me 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 = []
+ required_params = [
+ "ids",
+ ]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_reposts_of_me"
+ ), f"Required parameter '{required_param}' missing from get_by_ids"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "max_results",
- "pagination_token",
- "tweet.fields",
- "expansions",
- "media.fields",
- "poll.fields",
"user.fields",
- "place.fields",
+ "expansions",
+ "tweet.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -1188,69 +1161,46 @@ def test_get_reposts_of_me_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- 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")
+ 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_reposts_of_me should have return type annotation"
+ ), f"Method get_by_ids should have return type annotation"
- 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 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_of_me should have pagination parameters"
-
-
- def test_get_bookmarks_exists(self):
- """Test that get_bookmarks method exists with correct signature."""
+ def test_get_bookmarks_by_folder_id_exists(self):
+ """Test that get_bookmarks_by_folder_id method exists with correct signature."""
# Check method exists
- method = getattr(UsersClient, "get_bookmarks", None)
- assert method is not None, f"Method get_bookmarks does not exist on UsersClient"
+ method = getattr(UsersClient, "get_bookmarks_by_folder_id", None)
+ assert (
+ method is not None
+ ), f"Method get_bookmarks_by_folder_id does not exist on UsersClient"
# Check method is callable
- assert callable(method), f"get_bookmarks is not callable"
+ assert callable(method), f"get_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_bookmarks should have at least 'self' parameter"
+ assert (
+ len(params) >= 1
+ ), f"get_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_bookmarks"
+ ), f"Required parameter '{required_param}' missing from get_bookmarks_by_folder_id"
# Check optional parameters have defaults (excluding 'self')
- optional_params = [
- "max_results",
- "pagination_token",
- "tweet.fields",
- "expansions",
- "media.fields",
- "poll.fields",
- "user.fields",
- "place.fields",
- ]
+ optional_params = []
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -1259,51 +1209,28 @@ def test_get_bookmarks_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_bookmarks_return_annotation(self):
- """Test that get_bookmarks has proper return type annotation."""
- method = getattr(UsersClient, "get_bookmarks")
+ def test_get_bookmarks_by_folder_id_return_annotation(self):
+ """Test that get_bookmarks_by_folder_id has proper return type annotation."""
+ method = getattr(UsersClient, "get_bookmarks_by_folder_id")
sig = inspect.signature(method)
# Check return annotation exists
assert (
sig.return_annotation is not inspect.Signature.empty
- ), f"Method get_bookmarks should have return type annotation"
-
-
- 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
- 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_bookmarks should have pagination parameters"
+ ), f"Method get_bookmarks_by_folder_id should have return type annotation"
- def test_create_bookmark_exists(self):
- """Test that create_bookmark 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, "create_bookmark", None)
- assert (
- method is not None
- ), f"Method create_bookmark 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"create_bookmark 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"create_bookmark 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]}'"
@@ -1314,7 +1241,7 @@ def test_create_bookmark_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from create_bookmark"
+ ), f"Required parameter '{required_param}' missing from unblock_dms"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -1325,41 +1252,43 @@ def test_create_bookmark_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_create_bookmark_return_annotation(self):
- """Test that create_bookmark has proper return type annotation."""
- method = getattr(UsersClient, "create_bookmark")
+ 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 create_bookmark should have return type annotation"
+ ), f"Method unblock_dms should have return type annotation"
- def test_get_by_ids_exists(self):
- """Test that get_by_ids 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_by_ids", None)
- assert method is not None, f"Method get_by_ids 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_by_ids 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_by_ids 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]}'"
# 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_by_ids"
+ ), f"Required parameter '{required_param}' missing from get_blocking"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
+ "max_results",
+ "pagination_token",
"user.fields",
"expansions",
"tweet.fields",
@@ -1372,39 +1301,62 @@ def test_get_by_ids_exists(self):
), 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")
+ 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_by_ids should have return type annotation"
+ ), f"Method get_blocking should have return type annotation"
- def test_get_by_id_exists(self):
- """Test that get_by_id method exists with correct signature."""
+ 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
+ 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_blocking should have pagination parameters"
+
+
+ def test_get_by_usernames_exists(self):
+ """Test that get_by_usernames 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"
+ method = getattr(UsersClient, "get_by_usernames", None)
+ assert (
+ method is not None
+ ), f"Method get_by_usernames does not exist on UsersClient"
# Check method is callable
- assert callable(method), f"get_by_id 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"get_by_id should have at least 'self' parameter"
+ assert (
+ len(params) >= 1
+ ), 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 get_by_id"
+ ), f"Required parameter '{required_param}' missing from get_by_usernames"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
"user.fields",
@@ -1419,48 +1371,42 @@ def test_get_by_id_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_by_id_return_annotation(self):
- """Test that get_by_id has proper return type annotation."""
- method = getattr(UsersClient, "get_by_id")
+ 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 get_by_id should have return type annotation"
+ ), f"Method get_by_usernames should have return type annotation"
- def test_get_bookmark_folders_exists(self):
- """Test that get_bookmark_folders method exists with correct signature."""
+ def test_unfollow_user_exists(self):
+ """Test that unfollow_user method exists with correct signature."""
# Check method exists
- method = getattr(UsersClient, "get_bookmark_folders", None)
- assert (
- method is not None
- ), f"Method get_bookmark_folders does not exist on UsersClient"
+ 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_bookmark_folders 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"get_bookmark_folders should have at least 'self' parameter"
+ assert len(params) >= 1, f"unfollow_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 = [
- "id",
+ "source_user_id",
+ "target_user_id",
]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_bookmark_folders"
+ ), f"Required parameter '{required_param}' missing from unfollow_user"
# 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]
@@ -1469,47 +1415,28 @@ def test_get_bookmark_folders_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_bookmark_folders_return_annotation(self):
- """Test that get_bookmark_folders has proper return type annotation."""
- method = getattr(UsersClient, "get_bookmark_folders")
+ 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 get_bookmark_folders should have return type annotation"
-
-
- def test_get_bookmark_folders_pagination_params(self):
- """Test that get_bookmark_folders has pagination parameters."""
- method = getattr(UsersClient, "get_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_bookmark_folders should have pagination parameters"
+ ), f"Method unfollow_user should have return type annotation"
- def test_unblock_dms_exists(self):
- """Test that unblock_dms 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, "unblock_dms", None)
- assert method is not None, f"Method unblock_dms does not exist on UsersClient"
+ 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"unblock_dms is not 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"unblock_dms should have at least 'self' parameter"
+ assert len(params) >= 1, f"block_dms should have at least 'self' parameter"
assert (
params[0] == "self"
), f"First parameter should be 'self', got '{params[0]}'"
@@ -1520,7 +1447,7 @@ def test_unblock_dms_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from unblock_dms"
+ ), f"Required parameter '{required_param}' missing from block_dms"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -1531,32 +1458,28 @@ def test_unblock_dms_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_unblock_dms_return_annotation(self):
- """Test that unblock_dms has proper return type annotation."""
- method = getattr(UsersClient, "unblock_dms")
+ 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 unblock_dms should have return type annotation"
+ ), f"Method block_dms should have return type annotation"
- def test_get_pinned_lists_exists(self):
- """Test that get_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(UsersClient, "get_pinned_lists", None)
- assert (
- method is not None
- ), f"Method get_pinned_lists does not exist on UsersClient"
+ 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_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_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]}'"
@@ -1567,12 +1490,14 @@ def test_get_pinned_lists_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_pinned_lists"
+ ), f"Required parameter '{required_param}' missing from get_followers"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
- "list.fields",
- "expansions",
+ "max_results",
+ "pagination_token",
"user.fields",
+ "expansions",
+ "tweet.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -1582,28 +1507,47 @@ def test_get_pinned_lists_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_pinned_lists_return_annotation(self):
- """Test that get_pinned_lists has proper return type annotation."""
- method = getattr(UsersClient, "get_pinned_lists")
+ 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_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(UsersClient, "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_by_id_exists(self):
+ """Test that get_by_id method exists with correct signature."""
# Check method exists
- method = getattr(UsersClient, "pin_list", None)
- assert method is not None, f"Method pin_list does not exist on UsersClient"
+ 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"pin_list 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"pin_list 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]}'"
@@ -1614,9 +1558,13 @@ 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_by_id"
# Check optional parameters have defaults (excluding 'self')
- optional_params = []
+ optional_params = [
+ "user.fields",
+ "expansions",
+ "tweet.fields",
+ ]
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -1625,32 +1573,32 @@ 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(UsersClient, "pin_list")
+ 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 pin_list should have return type annotation"
+ ), f"Method get_by_id should have return type annotation"
- def test_get_liked_posts_exists(self):
- """Test that get_liked_posts method exists with correct signature."""
+ def test_get_bookmark_folders_exists(self):
+ """Test that get_bookmark_folders method exists with correct signature."""
# Check method exists
- method = getattr(UsersClient, "get_liked_posts", None)
+ method = getattr(UsersClient, "get_bookmark_folders", None)
assert (
method is not None
- ), f"Method get_liked_posts does not exist on UsersClient"
+ ), f"Method get_bookmark_folders does not exist on UsersClient"
# Check method is callable
- assert callable(method), f"get_liked_posts is not callable"
+ assert callable(method), f"get_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_liked_posts should have at least 'self' parameter"
+ ), f"get_bookmark_folders should have at least 'self' parameter"
assert (
params[0] == "self"
), f"First parameter should be 'self', got '{params[0]}'"
@@ -1661,17 +1609,11 @@ def test_get_liked_posts_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_liked_posts"
+ ), f"Required parameter '{required_param}' missing from get_bookmark_folders"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
"max_results",
"pagination_token",
- "tweet.fields",
- "expansions",
- "media.fields",
- "poll.fields",
- "user.fields",
- "place.fields",
]
for optional_param in optional_params:
if optional_param in params:
@@ -1681,19 +1623,19 @@ def test_get_liked_posts_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_liked_posts_return_annotation(self):
- """Test that get_liked_posts has proper return type annotation."""
- method = getattr(UsersClient, "get_liked_posts")
+ def test_get_bookmark_folders_return_annotation(self):
+ """Test that get_bookmark_folders has proper return type annotation."""
+ method = getattr(UsersClient, "get_bookmark_folders")
sig = inspect.signature(method)
# Check return annotation exists
assert (
sig.return_annotation is not inspect.Signature.empty
- ), f"Method get_liked_posts should have return type annotation"
+ ), f"Method get_bookmark_folders should have return type annotation"
- def test_get_liked_posts_pagination_params(self):
- """Test that get_liked_posts has pagination parameters."""
- method = getattr(UsersClient, "get_liked_posts")
+ def test_get_bookmark_folders_pagination_params(self):
+ """Test that get_bookmark_folders has pagination parameters."""
+ method = getattr(UsersClient, "get_bookmark_folders")
sig = inspect.signature(method)
params = list(sig.parameters.keys())
# Should have pagination-related parameters
@@ -1707,39 +1649,40 @@ def test_get_liked_posts_pagination_params(self):
has_pagination_param = any(param in params for param in pagination_params)
assert (
has_pagination_param
- ), f"Paginated method get_liked_posts should have pagination parameters"
+ ), f"Paginated method get_bookmark_folders should have pagination parameters"
- def test_get_bookmarks_by_folder_id_exists(self):
- """Test that get_bookmarks_by_folder_id method exists with correct signature."""
+ def test_get_following_exists(self):
+ """Test that get_following method exists with correct signature."""
# Check method exists
- method = getattr(UsersClient, "get_bookmarks_by_folder_id", None)
- assert (
- method is not None
- ), f"Method get_bookmarks_by_folder_id does not exist on UsersClient"
+ 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_bookmarks_by_folder_id is not 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_bookmarks_by_folder_id should have at least 'self' 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]}'"
# 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_bookmarks_by_folder_id"
+ ), f"Required parameter '{required_param}' missing from get_following"
# Check optional parameters have defaults (excluding 'self')
- optional_params = []
+ optional_params = [
+ "max_results",
+ "pagination_token",
+ "user.fields",
+ "expansions",
+ "tweet.fields",
+ ]
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -1748,28 +1691,47 @@ def test_get_bookmarks_by_folder_id_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_bookmarks_by_folder_id_return_annotation(self):
- """Test that get_bookmarks_by_folder_id has proper return type annotation."""
- method = getattr(UsersClient, "get_bookmarks_by_folder_id")
+ 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_bookmarks_by_folder_id should have return type annotation"
+ ), f"Method get_following should have return type annotation"
- def test_like_post_exists(self):
- """Test that like_post method exists with correct signature."""
+ 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
+ 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_following should have pagination parameters"
+
+
+ def test_follow_user_exists(self):
+ """Test that follow_user method exists with correct signature."""
# Check method exists
- method = getattr(UsersClient, "like_post", None)
- assert method is not None, f"Method like_post 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"like_post 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"like_post 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]}'"
@@ -1780,7 +1742,7 @@ def test_like_post_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from like_post"
+ ), f"Required parameter '{required_param}' missing from follow_user"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -1791,42 +1753,55 @@ def test_like_post_exists(self):
), 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(UsersClient, "like_post")
+ 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 like_post should have return type annotation"
+ ), f"Method follow_user should have return type annotation"
- def test_unpin_list_exists(self):
- """Test that unpin_list method exists with correct signature."""
+ def test_get_timeline_exists(self):
+ """Test that get_timeline method exists with correct signature."""
# Check method exists
- method = getattr(UsersClient, "unpin_list", None)
- assert method is not None, f"Method unpin_list does not exist on UsersClient"
+ 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"unpin_list 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"unpin_list 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]}'"
# 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"
+ ), f"Required parameter '{required_param}' missing from get_timeline"
# Check optional parameters have defaults (excluding 'self')
- optional_params = []
+ optional_params = [
+ "since_id",
+ "until_id",
+ "max_results",
+ "pagination_token",
+ "exclude",
+ "start_time",
+ "end_time",
+ "tweet.fields",
+ "expansions",
+ "media.fields",
+ "poll.fields",
+ "user.fields",
+ "place.fields",
+ ]
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -1835,45 +1810,62 @@ 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(UsersClient, "unpin_list")
+ 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 unpin_list should have return type annotation"
+ ), f"Method get_timeline should have return type annotation"
- 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)
+ 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
+ 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_by_username does not exist on UsersClient"
+ has_pagination_param
+ ), f"Paginated method get_timeline 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_by_username 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_by_username 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 = [
- "username",
+ "query",
]
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from get_by_username"
+ ), f"Required parameter '{required_param}' missing from search"
# Check optional parameters have defaults (excluding 'self')
optional_params = [
+ "max_results",
+ "next_token",
"user.fields",
"expansions",
"tweet.fields",
@@ -1886,76 +1878,47 @@ def test_get_by_username_exists(self):
), 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")
+ 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_by_username should have return type annotation"
+ ), f"Method search should have return type annotation"
- def test_delete_bookmark_exists(self):
- """Test that delete_bookmark method exists with correct signature."""
- # Check method exists
- method = getattr(UsersClient, "delete_bookmark", None)
- assert (
- method is not None
- ), f"Method delete_bookmark does not exist on UsersClient"
- # Check method is callable
- assert callable(method), f"delete_bookmark is not callable"
- # Check method signature
+ 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 'self' as first parameter
- assert (
- len(params) >= 1
- ), f"delete_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",
+ # 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 delete_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_bookmark_return_annotation(self):
- """Test that delete_bookmark has proper return type annotation."""
- method = getattr(UsersClient, "delete_bookmark")
- 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 delete_bookmark should have return type annotation"
+ has_pagination_param
+ ), f"Paginated method search should have pagination parameters"
- def test_block_dms_exists(self):
- """Test that block_dms 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, "block_dms", None)
- assert method is not None, f"Method block_dms 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"block_dms 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"block_dms 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]}'"
@@ -1966,9 +1929,18 @@ def test_block_dms_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from block_dms"
+ ), f"Required parameter '{required_param}' missing from get_bookmarks"
# Check optional parameters have defaults (excluding 'self')
- optional_params = []
+ optional_params = [
+ "max_results",
+ "pagination_token",
+ "tweet.fields",
+ "expansions",
+ "media.fields",
+ "poll.fields",
+ "user.fields",
+ "place.fields",
+ ]
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -1977,28 +1949,51 @@ def test_block_dms_exists(self):
), 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")
+ 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 block_dms should have return type annotation"
+ ), f"Method get_bookmarks should have return type annotation"
- def test_repost_post_exists(self):
- """Test that repost_post method exists with correct signature."""
+ 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
+ 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_bookmarks should have pagination parameters"
+
+
+ def test_create_bookmark_exists(self):
+ """Test that create_bookmark method exists with correct signature."""
# Check method exists
- method = getattr(UsersClient, "repost_post", None)
- assert method is not None, f"Method repost_post does not exist on UsersClient"
+ method = getattr(UsersClient, "create_bookmark", None)
+ assert (
+ method is not None
+ ), f"Method create_bookmark does not exist on UsersClient"
# Check method is callable
- assert callable(method), f"repost_post is not callable"
+ assert callable(method), f"create_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"repost_post should have at least 'self' parameter"
+ assert (
+ len(params) >= 1
+ ), f"create_bookmark should have at least 'self' parameter"
assert (
params[0] == "self"
), f"First parameter should be 'self', got '{params[0]}'"
@@ -2009,7 +2004,7 @@ def test_repost_post_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from repost_post"
+ ), f"Required parameter '{required_param}' missing from create_bookmark"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -2020,42 +2015,52 @@ def test_repost_post_exists(self):
), 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(UsersClient, "repost_post")
+ def test_create_bookmark_return_annotation(self):
+ """Test that create_bookmark has proper return type annotation."""
+ method = getattr(UsersClient, "create_bookmark")
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"
+ ), f"Method create_bookmark should have return type annotation"
- def test_unfollow_user_exists(self):
- """Test that unfollow_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, "unfollow_user", None)
- assert method is not None, f"Method unfollow_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"unfollow_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"unfollow_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 = [
- "source_user_id",
- "target_user_id",
- ]
+ required_params = []
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_reposts_of_me"
# Check optional parameters have defaults (excluding 'self')
- optional_params = []
+ optional_params = [
+ "max_results",
+ "pagination_token",
+ "tweet.fields",
+ "expansions",
+ "media.fields",
+ "poll.fields",
+ "user.fields",
+ "place.fields",
+ ]
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -2064,47 +2069,61 @@ 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_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 unfollow_user should have return type annotation"
+ ), f"Method get_reposts_of_me should have return type annotation"
- def test_get_followers_exists(self):
- """Test that get_followers method exists with correct 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 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_of_me should have pagination parameters"
+
+
+ def test_unpin_list_exists(self):
+ """Test that unpin_list 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"
+ method = getattr(UsersClient, "unpin_list", None)
+ assert method is not None, f"Method unpin_list does not exist on UsersClient"
# Check method is callable
- assert callable(method), f"get_followers 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"get_followers 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]}'"
# 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 get_followers"
+ ), f"Required parameter '{required_param}' missing from unpin_list"
# Check optional parameters have defaults (excluding 'self')
- optional_params = [
- "max_results",
- "pagination_token",
- "user.fields",
- "expansions",
- "tweet.fields",
- ]
+ optional_params = []
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -2113,76 +2132,57 @@ def test_get_followers_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_get_followers_return_annotation(self):
- """Test that get_followers has proper return type annotation."""
- method = getattr(UsersClient, "get_followers")
+ def test_unpin_list_return_annotation(self):
+ """Test that unpin_list has proper return type annotation."""
+ method = getattr(UsersClient, "unpin_list")
sig = inspect.signature(method)
# Check return annotation exists
assert (
sig.return_annotation is not inspect.Signature.empty
- ), f"Method get_followers should have return type annotation"
-
-
- 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
- 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"
+ ), 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_me",
- "unfollow_list",
+ "like_post",
+ "unlike_post",
"get_muting",
"mute_user",
- "unlike_post",
- "get_posts",
- "get_following",
- "follow_user",
- "get_timeline",
+ "get_pinned_lists",
+ "pin_list",
+ "unrepost_post",
"unmute_user",
- "search",
- "get_owned_lists",
- "get_by_usernames",
- "get_mentions",
+ "delete_bookmark",
"get_list_memberships",
- "get_blocking",
+ "get_me",
+ "get_liked_posts",
+ "get_posts",
"get_followed_lists",
"follow_list",
- "unrepost_post",
- "get_reposts_of_me",
- "get_bookmarks",
- "create_bookmark",
- "get_by_ids",
- "get_by_id",
- "get_bookmark_folders",
- "unblock_dms",
- "get_pinned_lists",
- "pin_list",
- "get_liked_posts",
- "get_bookmarks_by_folder_id",
- "like_post",
- "unpin_list",
"get_by_username",
- "delete_bookmark",
- "block_dms",
+ "get_mentions",
+ "get_owned_lists",
"repost_post",
+ "unfollow_list",
+ "get_by_ids",
+ "get_bookmarks_by_folder_id",
+ "unblock_dms",
+ "get_blocking",
+ "get_by_usernames",
"unfollow_user",
+ "block_dms",
"get_followers",
+ "get_by_id",
+ "get_bookmark_folders",
+ "get_following",
+ "follow_user",
+ "get_timeline",
+ "search",
+ "get_bookmarks",
+ "create_bookmark",
+ "get_reposts_of_me",
+ "unpin_list",
]
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 7cf73d0e..14871766 100644
--- a/xdk/python/tests/webhooks/test_contracts.py
+++ b/xdk/python/tests/webhooks/test_contracts.py
@@ -142,8 +142,8 @@ def test_get_stream_links_response_structure(self):
)
- def test_validate_request_structure(self):
- """Test validate request structure."""
+ def test_create_stream_link_request_structure(self):
+ """Test create_stream_link request structure."""
# Mock the session to capture request details
with patch.object(self.client, "session") as mock_session:
mock_response = Mock()
@@ -152,7 +152,7 @@ def test_validate_request_structure(self):
"data": None,
}
mock_response.raise_for_status.return_value = None
- mock_session.put.return_value = mock_response
+ mock_session.post.return_value = mock_response
# Prepare test parameters
kwargs = {}
# Add required parameters
@@ -160,7 +160,7 @@ def test_validate_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.webhooks_client, "validate")
+ method = getattr(self.webhooks_client, "create_stream_link")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -179,7 +179,7 @@ def test_validate_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.put.return_value = mock_streaming_response
+ mock_session.post.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -188,14 +188,14 @@ def test_validate_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# Verify the request was made
- mock_session.put.assert_called_once()
+ mock_session.post.assert_called_once()
# Verify request structure
- call_args = mock_session.put.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/tweets/search/webhooks/{webhook_id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -211,12 +211,12 @@ def test_validate_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for validate: {e}")
+ pytest.fail(f"Contract test failed for create_stream_link: {e}")
- def test_validate_required_parameters(self):
- """Test that validate handles parameters correctly."""
- method = getattr(self.webhooks_client, "validate")
+ def test_create_stream_link_required_parameters(self):
+ """Test that create_stream_link handles parameters correctly."""
+ method = getattr(self.webhooks_client, "create_stream_link")
# 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)
@@ -224,14 +224,14 @@ def test_validate_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.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_validate_response_structure(self):
- """Test validate response structure validation."""
+ def test_create_stream_link_response_structure(self):
+ """Test create_stream_link response structure validation."""
with patch.object(self.client, "session") as mock_session:
# Create mock response with expected structure
mock_response_data = {
@@ -241,13 +241,13 @@ def test_validate_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.post.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")
+ method = getattr(self.webhooks_client, "create_stream_link")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -259,8 +259,8 @@ def test_validate_response_structure(self):
)
- def test_delete_request_structure(self):
- """Test delete request structure."""
+ def test_delete_stream_link_request_structure(self):
+ """Test delete_stream_link request structure."""
# Mock the session to capture request details
with patch.object(self.client, "session") as mock_session:
mock_response = Mock()
@@ -277,7 +277,7 @@ def test_delete_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.webhooks_client, "delete")
+ method = getattr(self.webhooks_client, "delete_stream_link")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -312,7 +312,7 @@ def test_delete_request_structure(self):
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/tweets/search/webhooks/{webhook_id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -328,12 +328,12 @@ def test_delete_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for delete: {e}")
+ pytest.fail(f"Contract test failed for delete_stream_link: {e}")
- def test_delete_required_parameters(self):
- """Test that delete handles parameters correctly."""
- method = getattr(self.webhooks_client, "delete")
+ def test_delete_stream_link_required_parameters(self):
+ """Test that delete_stream_link handles parameters correctly."""
+ method = getattr(self.webhooks_client, "delete_stream_link")
# 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,8 +347,8 @@ def test_delete_required_parameters(self):
method()
- def test_delete_response_structure(self):
- """Test delete response structure validation."""
+ def test_delete_stream_link_response_structure(self):
+ """Test delete_stream_link response structure validation."""
with patch.object(self.client, "session") as mock_session:
# Create mock response with expected structure
mock_response_data = {
@@ -364,7 +364,7 @@ def test_delete_response_structure(self):
kwargs["webhook_id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.webhooks_client, "delete")
+ method = getattr(self.webhooks_client, "delete_stream_link")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
@@ -614,8 +614,8 @@ def test_create_response_structure(self):
)
- def test_create_stream_link_request_structure(self):
- """Test create_stream_link 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()
@@ -624,7 +624,7 @@ def test_create_stream_link_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
@@ -632,7 +632,7 @@ def test_create_stream_link_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.webhooks_client, "create_stream_link")
+ method = getattr(self.webhooks_client, "validate")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -651,7 +651,7 @@ def test_create_stream_link_request_structure(self):
test_data = '{"data": "test"}\n'
mock_streaming_response.iter_content.return_value = [test_data]
# Update the session mock to return our streaming response
- mock_session.post.return_value = mock_streaming_response
+ mock_session.put.return_value = mock_streaming_response
# Consume the generator to trigger the HTTP request
try:
next(result)
@@ -660,14 +660,14 @@ def test_create_stream_link_request_structure(self):
except Exception:
pass # Ignore other exceptions in test data processing
# 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/tweets/search/webhooks/{webhook_id}"
+ expected_path = "/2/webhooks/{webhook_id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -683,12 +683,12 @@ def test_create_stream_link_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for create_stream_link: {e}")
+ pytest.fail(f"Contract test failed for validate: {e}")
- def test_create_stream_link_required_parameters(self):
- """Test that create_stream_link handles parameters correctly."""
- method = getattr(self.webhooks_client, "create_stream_link")
+ 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)
@@ -696,14 +696,14 @@ def test_create_stream_link_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_create_stream_link_response_structure(self):
- """Test create_stream_link 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 = {
@@ -713,13 +713,13 @@ def test_create_stream_link_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["webhook_id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.webhooks_client, "create_stream_link")
+ 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
@@ -731,8 +731,8 @@ def test_create_stream_link_response_structure(self):
)
- def test_delete_stream_link_request_structure(self):
- """Test delete_stream_link 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()
@@ -749,7 +749,7 @@ def test_delete_stream_link_request_structure(self):
# Add request body if required
# Call the method
try:
- method = getattr(self.webhooks_client, "delete_stream_link")
+ method = getattr(self.webhooks_client, "delete")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
@@ -784,7 +784,7 @@ def test_delete_stream_link_request_structure(self):
called_url = (
call_args[0][0] if call_args[0] else call_args[1].get("url", "")
)
- expected_path = "/2/tweets/search/webhooks/{webhook_id}"
+ expected_path = "/2/webhooks/{webhook_id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
@@ -800,12 +800,12 @@ def test_delete_stream_link_request_structure(self):
# For regular operations, verify we got a result
assert result is not None, "Method should return a result"
except Exception as e:
- pytest.fail(f"Contract test failed for delete_stream_link: {e}")
+ pytest.fail(f"Contract test failed for delete: {e}")
- def test_delete_stream_link_required_parameters(self):
- """Test that delete_stream_link handles parameters correctly."""
- method = getattr(self.webhooks_client, "delete_stream_link")
+ 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)
@@ -819,8 +819,8 @@ def test_delete_stream_link_required_parameters(self):
method()
- def test_delete_stream_link_response_structure(self):
- """Test delete_stream_link 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 = {
@@ -836,7 +836,7 @@ def test_delete_stream_link_response_structure(self):
kwargs["webhook_id"] = "test"
# Add request body if required
# Call method and verify response structure
- method = getattr(self.webhooks_client, "delete_stream_link")
+ 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_structure.py b/xdk/python/tests/webhooks/test_structure.py
index c4427843..88ed6213 100644
--- a/xdk/python/tests/webhooks/test_structure.py
+++ b/xdk/python/tests/webhooks/test_structure.py
@@ -73,18 +73,22 @@ def test_get_stream_links_return_annotation(self):
), f"Method get_stream_links should have return type annotation"
- def test_validate_exists(self):
- """Test that validate method exists with correct signature."""
+ def test_create_stream_link_exists(self):
+ """Test that create_stream_link method exists with correct signature."""
# Check method exists
- method = getattr(WebhooksClient, "validate", None)
- assert method is not None, f"Method validate does not exist on WebhooksClient"
+ method = getattr(WebhooksClient, "create_stream_link", None)
+ assert (
+ method is not None
+ ), f"Method create_stream_link does not exist on WebhooksClient"
# Check method is callable
- assert callable(method), f"validate is not callable"
+ assert callable(method), f"create_stream_link is not 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 should have at least 'self' parameter"
+ assert (
+ len(params) >= 1
+ ), f"create_stream_link should have at least 'self' parameter"
assert (
params[0] == "self"
), f"First parameter should be 'self', got '{params[0]}'"
@@ -95,9 +99,16 @@ def test_validate_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from validate"
+ ), f"Required parameter '{required_param}' missing from create_stream_link"
# Check optional parameters have defaults (excluding 'self')
- optional_params = []
+ optional_params = [
+ "tweet.fields",
+ "expansions",
+ "media.fields",
+ "poll.fields",
+ "user.fields",
+ "place.fields",
+ ]
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -106,28 +117,32 @@ def test_validate_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_validate_return_annotation(self):
- """Test that validate has proper return type annotation."""
- method = getattr(WebhooksClient, "validate")
+ def test_create_stream_link_return_annotation(self):
+ """Test that create_stream_link has proper return type annotation."""
+ method = getattr(WebhooksClient, "create_stream_link")
sig = inspect.signature(method)
# Check return annotation exists
assert (
sig.return_annotation is not inspect.Signature.empty
- ), f"Method validate should have return type annotation"
+ ), f"Method create_stream_link should have return type annotation"
- def test_delete_exists(self):
- """Test that delete method exists with correct signature."""
+ def test_delete_stream_link_exists(self):
+ """Test that delete_stream_link method exists with correct signature."""
# Check method exists
- method = getattr(WebhooksClient, "delete", None)
- assert method is not None, f"Method delete does not exist on WebhooksClient"
+ method = getattr(WebhooksClient, "delete_stream_link", None)
+ assert (
+ method is not None
+ ), f"Method delete_stream_link does not exist on WebhooksClient"
# Check method is callable
- assert callable(method), f"delete is not callable"
+ assert callable(method), f"delete_stream_link is not 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 should have at least 'self' parameter"
+ assert (
+ len(params) >= 1
+ ), f"delete_stream_link should have at least 'self' parameter"
assert (
params[0] == "self"
), f"First parameter should be 'self', got '{params[0]}'"
@@ -138,7 +153,7 @@ def test_delete_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from delete"
+ ), f"Required parameter '{required_param}' missing from delete_stream_link"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -149,14 +164,14 @@ def test_delete_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_delete_return_annotation(self):
- """Test that delete has proper return type annotation."""
- method = getattr(WebhooksClient, "delete")
+ def test_delete_stream_link_return_annotation(self):
+ """Test that delete_stream_link has proper return type annotation."""
+ method = getattr(WebhooksClient, "delete_stream_link")
sig = inspect.signature(method)
# Check return annotation exists
assert (
sig.return_annotation is not inspect.Signature.empty
- ), f"Method delete should have return type annotation"
+ ), f"Method delete_stream_link should have return type annotation"
def test_get_exists(self):
@@ -243,22 +258,18 @@ def test_create_return_annotation(self):
), f"Method create should have return type annotation"
- def test_create_stream_link_exists(self):
- """Test that create_stream_link method exists with correct signature."""
+ def test_validate_exists(self):
+ """Test that validate method exists with correct signature."""
# Check method exists
- method = getattr(WebhooksClient, "create_stream_link", None)
- assert (
- method is not None
- ), f"Method create_stream_link 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"create_stream_link 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"create_stream_link 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]}'"
@@ -269,16 +280,9 @@ def test_create_stream_link_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from create_stream_link"
+ ), f"Required parameter '{required_param}' missing from validate"
# Check optional parameters have defaults (excluding 'self')
- optional_params = [
- "tweet.fields",
- "expansions",
- "media.fields",
- "poll.fields",
- "user.fields",
- "place.fields",
- ]
+ optional_params = []
for optional_param in optional_params:
if optional_param in params:
param_obj = sig.parameters[optional_param]
@@ -287,32 +291,28 @@ def test_create_stream_link_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_create_stream_link_return_annotation(self):
- """Test that create_stream_link has proper return type annotation."""
- method = getattr(WebhooksClient, "create_stream_link")
+ 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 create_stream_link should have return type annotation"
+ ), f"Method validate should have return type annotation"
- def test_delete_stream_link_exists(self):
- """Test that delete_stream_link method exists with correct signature."""
+ def test_delete_exists(self):
+ """Test that delete method exists with correct signature."""
# Check method exists
- method = getattr(WebhooksClient, "delete_stream_link", None)
- assert (
- method is not None
- ), f"Method delete_stream_link 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"delete_stream_link 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"delete_stream_link 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]}'"
@@ -323,7 +323,7 @@ def test_delete_stream_link_exists(self):
for required_param in required_params:
assert (
required_param in params
- ), f"Required parameter '{required_param}' missing from delete_stream_link"
+ ), f"Required parameter '{required_param}' missing from delete"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
@@ -334,26 +334,26 @@ def test_delete_stream_link_exists(self):
), f"Optional parameter '{optional_param}' should have a default value"
- def test_delete_stream_link_return_annotation(self):
- """Test that delete_stream_link has proper return type annotation."""
- method = getattr(WebhooksClient, "delete_stream_link")
+ 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 delete_stream_link 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 = [
"get_stream_links",
- "validate",
- "delete",
- "get",
- "create",
"create_stream_link",
"delete_stream_link",
+ "get",
+ "create",
+ "validate",
+ "delete",
]
for expected_method in expected_methods:
assert hasattr(
diff --git a/xdk/python/xdk/account_activity/client.py b/xdk/python/xdk/account_activity/client.py
index 1ae1a682..b2c8b52c 100644
--- a/xdk/python/xdk/account_activity/client.py
+++ b/xdk/python/xdk/account_activity/client.py
@@ -21,13 +21,13 @@
if TYPE_CHECKING:
from ..client import Client
from .models import (
+ DeleteSubscriptionResponse,
+ GetSubscriptionCountResponse,
+ CreateReplayJobResponse,
ValidateSubscriptionResponse,
CreateSubscriptionRequest,
CreateSubscriptionResponse,
- DeleteSubscriptionResponse,
GetSubscriptionsResponse,
- CreateReplayJobResponse,
- GetSubscriptionCountResponse,
)
@@ -39,106 +39,6 @@ def __init__(self, client: Client):
self.client = client
- def validate_subscription(self, 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:
- ValidateSubscriptionResponse: Response data
- """
- url = (
- self.client.base_url
- + "/2/account_activity/webhooks/{webhook_id}/subscriptions/all"
- )
- url = url.replace("{webhook_id}", str(webhook_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 = {}
- headers = {}
- # Prepare request data
- json_data = None
- # 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 ValidateSubscriptionResponse.model_validate(response_data)
-
-
- def create_subscription(
- self, webhook_id: Any, body: Optional[CreateSubscriptionRequest] = None
- ) -> CreateSubscriptionResponse:
- """
- 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:
- CreateSubscriptionResponse: Response data
- """
- url = (
- self.client.base_url
- + "/2/account_activity/webhooks/{webhook_id}/subscriptions/all"
- )
- url = url.replace("{webhook_id}", str(webhook_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 = {}
- headers = {}
- headers["Content-Type"] = "application/json"
- # Prepare request data
- json_data = None
- if body is not None:
- json_data = (
- body.model_dump(exclude_none=True)
- if hasattr(body, "model_dump")
- else body
- )
- # Make the request
- if self.client.oauth2_session:
- response = self.client.oauth2_session.post(
- url,
- params=params,
- headers=headers,
- json=json_data,
- )
- else:
- response = self.client.session.post(
- url,
- params=params,
- headers=headers,
- json=json_data,
- )
- # Check for errors
- response.raise_for_status()
- # Parse the response data
- response_data = response.json()
- # Convert to Pydantic model if applicable
- return CreateSubscriptionResponse.model_validate(response_data)
-
-
def delete_subscription(
self, webhook_id: Any, user_id: Any
) -> DeleteSubscriptionResponse:
@@ -183,20 +83,16 @@ def delete_subscription(
return DeleteSubscriptionResponse.model_validate(response_data)
- def get_subscriptions(self, webhook_id: Any) -> GetSubscriptionsResponse:
+ def get_subscription_count(
+ self,
+ ) -> GetSubscriptionCountResponse:
"""
- Get subscriptions
- Retrieves a list of all active subscriptions for a given webhook.
- Args:
- webhook_id: The webhook ID to pull subscriptions for.
- Returns:
- GetSubscriptionsResponse: Response data
+ Get subscription count
+ Retrieves a count of currently active Account Activity subscriptions.
+ Returns:
+ GetSubscriptionCountResponse: Response data
"""
- url = (
- self.client.base_url
- + "/2/account_activity/webhooks/{webhook_id}/subscriptions/all/list"
- )
- url = url.replace("{webhook_id}", str(webhook_id))
+ 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}"
@@ -220,7 +116,7 @@ def get_subscriptions(self, webhook_id: Any) -> GetSubscriptionsResponse:
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetSubscriptionsResponse.model_validate(response_data)
+ return GetSubscriptionCountResponse.model_validate(response_data)
def create_replay_job(
@@ -271,16 +167,120 @@ def create_replay_job(
return CreateReplayJobResponse.model_validate(response_data)
- def get_subscription_count(
- self,
- ) -> GetSubscriptionCountResponse:
+ def validate_subscription(self, webhook_id: Any) -> ValidateSubscriptionResponse:
"""
- Get subscription count
- Retrieves a count of currently active Account Activity subscriptions.
+ Validate subscription
+ Checks a user’s Account Activity subscription for a given webhook.
+ Args:
+ webhook_id: The webhook ID to check subscription against.
+ Returns:
+ ValidateSubscriptionResponse: Response data
+ """
+ url = (
+ self.client.base_url
+ + "/2/account_activity/webhooks/{webhook_id}/subscriptions/all"
+ )
+ url = url.replace("{webhook_id}", str(webhook_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 = {}
+ headers = {}
+ # Prepare request data
+ json_data = None
+ # 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 ValidateSubscriptionResponse.model_validate(response_data)
+
+
+ def create_subscription(
+ self, webhook_id: Any, body: Optional[CreateSubscriptionRequest] = None
+ ) -> CreateSubscriptionResponse:
+ """
+ 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:
- GetSubscriptionCountResponse: Response data
+ CreateSubscriptionResponse: Response data
"""
- url = self.client.base_url + "/2/account_activity/subscriptions/count"
+ url = (
+ self.client.base_url
+ + "/2/account_activity/webhooks/{webhook_id}/subscriptions/all"
+ )
+ url = url.replace("{webhook_id}", str(webhook_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 = {}
+ headers = {}
+ headers["Content-Type"] = "application/json"
+ # Prepare request data
+ json_data = None
+ if body is not None:
+ json_data = (
+ body.model_dump(exclude_none=True)
+ if hasattr(body, "model_dump")
+ else body
+ )
+ # Make the request
+ if self.client.oauth2_session:
+ response = self.client.oauth2_session.post(
+ url,
+ params=params,
+ headers=headers,
+ json=json_data,
+ )
+ else:
+ response = self.client.session.post(
+ url,
+ params=params,
+ headers=headers,
+ json=json_data,
+ )
+ # Check for errors
+ response.raise_for_status()
+ # Parse the response data
+ response_data = response.json()
+ # Convert to Pydantic model if applicable
+ return CreateSubscriptionResponse.model_validate(response_data)
+
+
+ def get_subscriptions(self, 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:
+ GetSubscriptionsResponse: Response data
+ """
+ url = (
+ self.client.base_url
+ + "/2/account_activity/webhooks/{webhook_id}/subscriptions/all/list"
+ )
+ url = url.replace("{webhook_id}", str(webhook_id))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
f"Bearer {self.client.bearer_token}"
@@ -304,4 +304,4 @@ def get_subscription_count(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetSubscriptionCountResponse.model_validate(response_data)
+ return GetSubscriptionsResponse.model_validate(response_data)
diff --git a/xdk/python/xdk/account_activity/models.py b/xdk/python/xdk/account_activity/models.py
index 51677ec1..c70927a7 100644
--- a/xdk/python/xdk/account_activity/models.py
+++ b/xdk/python/xdk/account_activity/models.py
@@ -16,61 +16,61 @@
from datetime import datetime
-# Models for validate_subscription
+# Models for delete_subscription
-class ValidateSubscriptionResponse(BaseModel):
- """Response model for validate_subscription"""
+class DeleteSubscriptionResponse(BaseModel):
+ """Response model for delete_subscription"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for create_subscription
-
-
-class CreateSubscriptionRequest(BaseModel):
- """Request model for create_subscription"""
-
- model_config = ConfigDict(populate_by_name=True)
+# Models for get_subscription_count
-class CreateSubscriptionResponse(BaseModel):
- """Response model for create_subscription"""
+class GetSubscriptionCountResponse(BaseModel):
+ """Response model for get_subscription_count"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for delete_subscription
+# Models for create_replay_job
-class DeleteSubscriptionResponse(BaseModel):
- """Response model for delete_subscription"""
+class CreateReplayJobResponse(BaseModel):
+ """Response model for create_replay_job"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_subscriptions
+# Models for validate_subscription
-class GetSubscriptionsResponse(BaseModel):
- """Response model for get_subscriptions"""
+class ValidateSubscriptionResponse(BaseModel):
+ """Response model for validate_subscription"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for create_replay_job
+# Models for create_subscription
-class CreateReplayJobResponse(BaseModel):
- """Response model for create_replay_job"""
+class CreateSubscriptionRequest(BaseModel):
+ """Request model for create_subscription"""
+
+ model_config = ConfigDict(populate_by_name=True)
+
+
+class CreateSubscriptionResponse(BaseModel):
+ """Response model for create_subscription"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_subscription_count
+# Models for get_subscriptions
-class GetSubscriptionCountResponse(BaseModel):
- """Response model for get_subscription_count"""
+class GetSubscriptionsResponse(BaseModel):
+ """Response model for get_subscriptions"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
diff --git a/xdk/python/xdk/activity/client.py b/xdk/python/xdk/activity/client.py
index b6299ccb..3f43fe6e 100644
--- a/xdk/python/xdk/activity/client.py
+++ b/xdk/python/xdk/activity/client.py
@@ -32,12 +32,12 @@
from ..client import Client
from .models import (
StreamResponse,
- GetSubscriptionsResponse,
- CreateSubscriptionRequest,
- CreateSubscriptionResponse,
UpdateSubscriptionRequest,
UpdateSubscriptionResponse,
DeleteSubscriptionResponse,
+ GetSubscriptionsResponse,
+ CreateSubscriptionRequest,
+ CreateSubscriptionResponse,
)
@@ -147,16 +147,20 @@ def stream(
raise
- def get_subscriptions(
- self,
- ) -> GetSubscriptionsResponse:
+ def update_subscription(
+ self, subscription_id: Any, body: Optional[UpdateSubscriptionRequest] = None
+ ) -> UpdateSubscriptionResponse:
"""
- Get X activity subscriptions
- Get a list of active subscriptions for XAA
+ Update X activity subscription
+ Updates a subscription for an X activity event
+ Args:
+ subscription_id: The ID of the subscription to update.
+ body: Request body
Returns:
- GetSubscriptionsResponse: Response data
+ UpdateSubscriptionResponse: Response data
"""
- url = self.client.base_url + "/2/activity/subscriptions"
+ url = self.client.base_url + "/2/activity/subscriptions/{subscription_id}"
+ url = url.replace("{subscription_id}", str(subscription_id))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
f"Bearer {self.client.bearer_token}"
@@ -167,33 +171,41 @@ def get_subscriptions(
)
params = {}
headers = {}
+ headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
+ if body is not None:
+ json_data = (
+ body.model_dump(exclude_none=True)
+ if hasattr(body, "model_dump")
+ else body
+ )
# Make the request
- response = self.client.session.get(
+ response = self.client.session.put(
url,
params=params,
headers=headers,
+ json=json_data,
)
# Check for errors
response.raise_for_status()
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetSubscriptionsResponse.model_validate(response_data)
+ return UpdateSubscriptionResponse.model_validate(response_data)
- def create_subscription(
- self, body: Optional[CreateSubscriptionRequest] = None
- ) -> CreateSubscriptionResponse:
+ def delete_subscription(self, subscription_id: Any) -> DeleteSubscriptionResponse:
"""
- Create X activity subscription
- Creates a subscription for an X activity event
- body: Request body
- Returns:
- CreateSubscriptionResponse: Response data
+ Deletes X activity subscription
+ Deletes a subscription for an X activity event
+ Args:
+ subscription_id: The ID of the subscription to delete.
+ Returns:
+ DeleteSubscriptionResponse: Response data
"""
- url = self.client.base_url + "/2/activity/subscriptions"
+ url = self.client.base_url + "/2/activity/subscriptions/{subscription_id}"
+ url = url.replace("{subscription_id}", str(subscription_id))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
f"Bearer {self.client.bearer_token}"
@@ -204,44 +216,32 @@ def create_subscription(
)
params = {}
headers = {}
- headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
- if body is not None:
- json_data = (
- body.model_dump(exclude_none=True)
- if hasattr(body, "model_dump")
- else body
- )
# Make the request
- response = self.client.session.post(
+ response = self.client.session.delete(
url,
params=params,
headers=headers,
- json=json_data,
)
# Check for errors
response.raise_for_status()
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return CreateSubscriptionResponse.model_validate(response_data)
+ return DeleteSubscriptionResponse.model_validate(response_data)
- def update_subscription(
- self, subscription_id: Any, body: Optional[UpdateSubscriptionRequest] = None
- ) -> UpdateSubscriptionResponse:
+ def get_subscriptions(
+ self,
+ ) -> GetSubscriptionsResponse:
"""
- Update X activity subscription
- Updates a subscription for an X activity event
- Args:
- subscription_id: The ID of the subscription to update.
- body: Request body
+ Get X activity subscriptions
+ Get a list of active subscriptions for XAA
Returns:
- UpdateSubscriptionResponse: Response data
+ GetSubscriptionsResponse: Response data
"""
- url = self.client.base_url + "/2/activity/subscriptions/{subscription_id}"
- url = url.replace("{subscription_id}", str(subscription_id))
+ url = self.client.base_url + "/2/activity/subscriptions"
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
f"Bearer {self.client.bearer_token}"
@@ -252,41 +252,33 @@ def update_subscription(
)
params = {}
headers = {}
- headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
- if body is not None:
- json_data = (
- body.model_dump(exclude_none=True)
- if hasattr(body, "model_dump")
- else body
- )
# Make the request
- response = self.client.session.put(
+ response = self.client.session.get(
url,
params=params,
headers=headers,
- json=json_data,
)
# Check for errors
response.raise_for_status()
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return UpdateSubscriptionResponse.model_validate(response_data)
+ return GetSubscriptionsResponse.model_validate(response_data)
- def delete_subscription(self, subscription_id: Any) -> DeleteSubscriptionResponse:
+ def create_subscription(
+ self, body: Optional[CreateSubscriptionRequest] = None
+ ) -> CreateSubscriptionResponse:
"""
- Deletes X activity subscription
- Deletes a subscription for an X activity event
- Args:
- subscription_id: The ID of the subscription to delete.
- Returns:
- DeleteSubscriptionResponse: Response data
+ Create X activity subscription
+ Creates a subscription for an X activity event
+ body: Request body
+ Returns:
+ CreateSubscriptionResponse: Response data
"""
- url = self.client.base_url + "/2/activity/subscriptions/{subscription_id}"
- url = url.replace("{subscription_id}", str(subscription_id))
+ url = self.client.base_url + "/2/activity/subscriptions"
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
f"Bearer {self.client.bearer_token}"
@@ -297,17 +289,25 @@ def delete_subscription(self, subscription_id: Any) -> DeleteSubscriptionRespons
)
params = {}
headers = {}
+ headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
+ if body is not None:
+ json_data = (
+ body.model_dump(exclude_none=True)
+ if hasattr(body, "model_dump")
+ else body
+ )
# Make the request
- response = self.client.session.delete(
+ response = self.client.session.post(
url,
params=params,
headers=headers,
+ json=json_data,
)
# Check for errors
response.raise_for_status()
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return DeleteSubscriptionResponse.model_validate(response_data)
+ return CreateSubscriptionResponse.model_validate(response_data)
diff --git a/xdk/python/xdk/activity/models.py b/xdk/python/xdk/activity/models.py
index 7e98de67..c3e842ee 100644
--- a/xdk/python/xdk/activity/models.py
+++ b/xdk/python/xdk/activity/models.py
@@ -25,49 +25,49 @@ class StreamResponse(BaseModel):
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_subscriptions
+# Models for update_subscription
-class GetSubscriptionsResponse(BaseModel):
- """Response model for get_subscriptions"""
+class UpdateSubscriptionRequest(BaseModel):
+ """Request model for update_subscription"""
- model_config = ConfigDict(populate_by_name=True, extra="allow")
+ model_config = ConfigDict(populate_by_name=True)
-# Models for create_subscription
+class UpdateSubscriptionResponse(BaseModel):
+ """Response model for update_subscription"""
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
-class CreateSubscriptionRequest(BaseModel):
- """Request model for create_subscription"""
- model_config = ConfigDict(populate_by_name=True)
+# Models for delete_subscription
-class CreateSubscriptionResponse(BaseModel):
- """Response model for create_subscription"""
+class DeleteSubscriptionResponse(BaseModel):
+ """Response model for delete_subscription"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for update_subscription
+# Models for get_subscriptions
-class UpdateSubscriptionRequest(BaseModel):
- """Request model for update_subscription"""
+class GetSubscriptionsResponse(BaseModel):
+ """Response model for get_subscriptions"""
- model_config = ConfigDict(populate_by_name=True)
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
-class UpdateSubscriptionResponse(BaseModel):
- """Response model for update_subscription"""
+# Models for create_subscription
- model_config = ConfigDict(populate_by_name=True, extra="allow")
+class CreateSubscriptionRequest(BaseModel):
+ """Request model for create_subscription"""
-# Models for delete_subscription
+ model_config = ConfigDict(populate_by_name=True)
-class DeleteSubscriptionResponse(BaseModel):
- """Response model for delete_subscription"""
+class CreateSubscriptionResponse(BaseModel):
+ """Response model for create_subscription"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
diff --git a/xdk/python/xdk/client.py b/xdk/python/xdk/client.py
index 691b386a..fa82548c 100644
--- a/xdk/python/xdk/client.py
+++ b/xdk/python/xdk/client.py
@@ -17,40 +17,42 @@
from .oauth2_auth import OAuth2PKCEAuth
from .paginator import Cursor, cursor, PaginationError
-from .trends.client import TrendsClient
+from .news.client import NewsClient
-from .users.client import UsersClient
+from .communities.client import CommunitiesClient
-from .spaces.client import SpacesClient
+from .account_activity.client import AccountActivityClient
from .compliance.client import ComplianceClient
-from .communities.client import CommunitiesClient
+from .trends.client import TrendsClient
-from .account_activity.client import AccountActivityClient
+from .users.client import UsersClient
-from .connections.client import ConnectionsClient
+from .stream.client import StreamClient
-from .lists.client import ListsClient
+from .media.client import MediaClient
-from .usage.client import UsageClient
+from .direct_messages.client import DirectMessagesClient
-from .posts.client import PostsClient
+from .spaces.client import SpacesClient
-from .stream.client import StreamClient
+from .activity.client import ActivityClient
-from .general.client import GeneralClient
+from .usage.client import UsageClient
from .community_notes.client import CommunityNotesClient
-from .media.client import MediaClient
-
-from .activity.client import ActivityClient
+from .lists.client import ListsClient
-from .direct_messages.client import DirectMessagesClient
+from .posts.client import PostsClient
from .webhooks.client import WebhooksClient
+from .connections.client import ConnectionsClient
+
+from .general.client import GeneralClient
+
class Client:
"""Client for interacting with the X API."""
@@ -92,23 +94,24 @@ def __init__(
scope=scope,
)
# Initialize clients for each tag
- self.trends = TrendsClient(self)
- self.users = UsersClient(self)
- self.spaces = SpacesClient(self)
- self.compliance = ComplianceClient(self)
+ self.news = NewsClient(self)
self.communities = CommunitiesClient(self)
self.account_activity = AccountActivityClient(self)
- self.connections = ConnectionsClient(self)
- self.lists = ListsClient(self)
- self.usage = UsageClient(self)
- self.posts = PostsClient(self)
+ self.compliance = ComplianceClient(self)
+ self.trends = TrendsClient(self)
+ self.users = UsersClient(self)
self.stream = StreamClient(self)
- self.general = GeneralClient(self)
- self.community_notes = CommunityNotesClient(self)
self.media = MediaClient(self)
- self.activity = ActivityClient(self)
self.direct_messages = DirectMessagesClient(self)
+ self.spaces = SpacesClient(self)
+ self.activity = ActivityClient(self)
+ self.usage = UsageClient(self)
+ self.community_notes = CommunityNotesClient(self)
+ self.lists = ListsClient(self)
+ self.posts = PostsClient(self)
self.webhooks = WebhooksClient(self)
+ self.connections = ConnectionsClient(self)
+ self.general = GeneralClient(self)
@property
diff --git a/xdk/python/xdk/communities/client.py b/xdk/python/xdk/communities/client.py
index 652f23df..4f5008df 100644
--- a/xdk/python/xdk/communities/client.py
+++ b/xdk/python/xdk/communities/client.py
@@ -40,7 +40,7 @@ def search(
max_results: int = None,
next_token: Any = None,
pagination_token: Any = None,
- communityfields: List = None,
+ community_fields: List = None,
) -> SearchResponse:
"""
Search Communities
@@ -50,7 +50,7 @@ def search(
max_results: The maximum number of search results to be returned by a request.
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.
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.
- communityfields: A comma separated list of Community fields to display.
+ community_fields: A comma separated list of Community fields to display.
Returns:
SearchResponse: Response data
"""
@@ -69,8 +69,10 @@ def search(
params["next_token"] = next_token
if pagination_token is not None:
params["pagination_token"] = pagination_token
- if communityfields is not None:
- params["community.fields"] = ",".join(str(item) for item in communityfields)
+ if community_fields is not None:
+ params["community.fields"] = ",".join(
+ str(item) for item in community_fields
+ )
headers = {}
# Prepare request data
json_data = None
@@ -95,13 +97,13 @@ def search(
return SearchResponse.model_validate(response_data)
- def get_by_id(self, id: Any, communityfields: List = None) -> GetByIdResponse:
+ def get_by_id(self, id: Any, community_fields: List = None) -> GetByIdResponse:
"""
Get Community by ID
Retrieves details of a specific Community by its ID.
Args:
id: The ID of the Community.
- communityfields: A comma separated list of Community fields to display.
+ community_fields: A comma separated list of Community fields to display.
Returns:
GetByIdResponse: Response data
"""
@@ -121,8 +123,10 @@ def get_by_id(self, id: Any, communityfields: List = None) -> GetByIdResponse:
if self.client.is_token_expired():
self.client.refresh_token()
params = {}
- if communityfields is not None:
- params["community.fields"] = ",".join(str(item) for item in communityfields)
+ if community_fields is not None:
+ params["community.fields"] = ",".join(
+ str(item) for item in community_fields
+ )
headers = {}
# Prepare request data
json_data = None
diff --git a/xdk/python/xdk/community_notes/client.py b/xdk/python/xdk/community_notes/client.py
index 802561b5..43d16068 100644
--- a/xdk/python/xdk/community_notes/client.py
+++ b/xdk/python/xdk/community_notes/client.py
@@ -23,11 +23,11 @@
from .models import (
SearchEligiblePostsResponse,
DeleteResponse,
- EvaluateRequest,
- EvaluateResponse,
+ SearchWrittenResponse,
CreateRequest,
CreateResponse,
- SearchWrittenResponse,
+ EvaluateRequest,
+ EvaluateResponse,
)
@@ -44,12 +44,13 @@ def search_eligible_posts(
test_mode: bool,
pagination_token: str = None,
max_results: int = None,
- tweetfields: List = None,
+ post_selection: str = None,
+ tweet_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
) -> SearchEligiblePostsResponse:
"""
Search for Posts Eligible for Community Notes
@@ -58,12 +59,13 @@ def search_eligible_posts(
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.
pagination_token: Pagination token to get next set of posts eligible for notes.
max_results: Max results to return.
- tweetfields: A comma separated list of Tweet fields to display.
+ post_selection: The selection of posts to return. Valid values are 'feed_size: small' and 'feed_size: large'. Default is 'feed_size: small', only top AI writers have access to large size feed.
+ tweet_fields: A comma separated list of Tweet fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
Returns:
SearchEligiblePostsResponse: Response data
"""
@@ -80,18 +82,20 @@ def search_eligible_posts(
params["pagination_token"] = pagination_token
if max_results is not None:
params["max_results"] = max_results
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ if post_selection is not None:
+ params["post_selection"] = post_selection
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
+ 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 = {}
# Prepare request data
json_data = None
@@ -157,52 +161,61 @@ def delete(self, id: Any) -> DeleteResponse:
return DeleteResponse.model_validate(response_data)
- def evaluate(self, body: Optional[EvaluateRequest] = None) -> EvaluateResponse:
+ def search_written(
+ self,
+ test_mode: bool,
+ pagination_token: str = None,
+ max_results: int = None,
+ note_fields: List = None,
+ ) -> SearchWrittenResponse:
"""
- Evaluate a Community Note
- Endpoint to evaluate a community note.
- body: Request body
- Returns:
- EvaluateResponse: Response data
+ 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.
+ pagination_token: Pagination token to get next set of posts eligible for notes.
+ max_results: Max results to return.
+ note_fields: A comma separated list of Note fields to display.
+ Returns:
+ SearchWrittenResponse: Response data
"""
- url = self.client.base_url + "/2/evaluate_note"
+ 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 = {}
- headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
- if body is not None:
- json_data = (
- body.model_dump(exclude_none=True)
- if hasattr(body, "model_dump")
- else body
- )
# 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=json_data,
)
else:
- response = self.client.session.post(
+ response = self.client.session.get(
url,
params=params,
headers=headers,
- json=json_data,
)
# Check for errors
response.raise_for_status()
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return EvaluateResponse.model_validate(response_data)
+ return SearchWrittenResponse.model_validate(response_data)
def create(self, body: Optional[CreateRequest] = None) -> CreateResponse:
@@ -253,58 +266,49 @@ def create(self, body: Optional[CreateRequest] = None) -> CreateResponse:
return CreateResponse.model_validate(response_data)
- def search_written(
- self,
- test_mode: bool,
- pagination_token: str = None,
- max_results: int = None,
- notefields: List = None,
- ) -> SearchWrittenResponse:
+ def evaluate(self, body: Optional[EvaluateRequest] = None) -> EvaluateResponse:
"""
- 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.
- pagination_token: Pagination token to get next set of posts eligible for notes.
- max_results: Max results to return.
- notefields: A comma separated list of Note fields to display.
- Returns:
- SearchWrittenResponse: Response data
+ Evaluate a Community Note
+ Endpoint to evaluate a community note.
+ body: Request body
+ Returns:
+ EvaluateResponse: Response data
"""
- url = self.client.base_url + "/2/notes/search/notes_written"
+ url = self.client.base_url + "/2/evaluate_note"
# 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 notefields is not None:
- params["note.fields"] = ",".join(str(item) for item in notefields)
headers = {}
+ headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
+ if body is not None:
+ json_data = (
+ body.model_dump(exclude_none=True)
+ if hasattr(body, "model_dump")
+ else body
+ )
# 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=json_data,
)
else:
- response = self.client.session.get(
+ response = self.client.session.post(
url,
params=params,
headers=headers,
+ json=json_data,
)
# Check for errors
response.raise_for_status()
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return SearchWrittenResponse.model_validate(response_data)
+ return EvaluateResponse.model_validate(response_data)
diff --git a/xdk/python/xdk/community_notes/models.py b/xdk/python/xdk/community_notes/models.py
index 9871c3c2..6f5a1fc9 100644
--- a/xdk/python/xdk/community_notes/models.py
+++ b/xdk/python/xdk/community_notes/models.py
@@ -34,17 +34,11 @@ class DeleteResponse(BaseModel):
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for evaluate
-
-
-class EvaluateRequest(BaseModel):
- """Request model for evaluate"""
-
- model_config = ConfigDict(populate_by_name=True)
+# Models for search_written
-class EvaluateResponse(BaseModel):
- """Response model for evaluate"""
+class SearchWrittenResponse(BaseModel):
+ """Response model for search_written"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
@@ -64,10 +58,16 @@ class CreateResponse(BaseModel):
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for search_written
+# Models for evaluate
-class SearchWrittenResponse(BaseModel):
- """Response model for search_written"""
+class EvaluateRequest(BaseModel):
+ """Request model for evaluate"""
+
+ model_config = ConfigDict(populate_by_name=True)
+
+
+class EvaluateResponse(BaseModel):
+ """Response model for evaluate"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
diff --git a/xdk/python/xdk/compliance/client.py b/xdk/python/xdk/compliance/client.py
index f1b7b0ea..ede2e65c 100644
--- a/xdk/python/xdk/compliance/client.py
+++ b/xdk/python/xdk/compliance/client.py
@@ -37,7 +37,7 @@ def __init__(self, client: Client):
def get_jobs(
- self, type: str, status: str = None, compliance_jobfields: List = None
+ self, type: str, status: str = None, compliance_job_fields: List = None
) -> GetJobsResponse:
"""
Get Compliance Jobs
@@ -45,7 +45,7 @@ def get_jobs(
Args:
type: Type of Compliance Job to list.
status: Status of Compliance Job to list.
- compliance_jobfields: A comma separated list of ComplianceJob fields to display.
+ compliance_job_fields: A comma separated list of ComplianceJob fields to display.
Returns:
GetJobsResponse: Response data
"""
@@ -63,9 +63,9 @@ def get_jobs(
params["type"] = type
if status is not None:
params["status"] = status
- if compliance_jobfields is not None:
+ if compliance_job_fields is not None:
params["compliance_job.fields"] = ",".join(
- str(item) for item in compliance_jobfields
+ str(item) for item in compliance_job_fields
)
headers = {}
# Prepare request data
@@ -128,14 +128,14 @@ def create_jobs(self, body: CreateJobsRequest) -> CreateJobsResponse:
def get_jobs_by_id(
- self, id: Any, compliance_jobfields: List = None
+ self, id: Any, compliance_job_fields: List = None
) -> 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.
- compliance_jobfields: A comma separated list of ComplianceJob fields to display.
+ compliance_job_fields: A comma separated list of ComplianceJob fields to display.
Returns:
GetJobsByIdResponse: Response data
"""
@@ -150,9 +150,9 @@ def get_jobs_by_id(
f"Bearer {self.client.access_token}"
)
params = {}
- if compliance_jobfields is not None:
+ if compliance_job_fields is not None:
params["compliance_job.fields"] = ",".join(
- str(item) for item in compliance_jobfields
+ str(item) for item in compliance_job_fields
)
headers = {}
# Prepare request data
diff --git a/xdk/python/xdk/direct_messages/client.py b/xdk/python/xdk/direct_messages/client.py
index 8964dbfc..d4f8773f 100644
--- a/xdk/python/xdk/direct_messages/client.py
+++ b/xdk/python/xdk/direct_messages/client.py
@@ -21,12 +21,12 @@
if TYPE_CHECKING:
from ..client import Client
from .models import (
- GetEventsByParticipantIdResponse,
- CreateByConversationIdRequest,
- CreateByConversationIdResponse,
GetEventsByConversationIdResponse,
CreateConversationRequest,
CreateConversationResponse,
+ CreateByConversationIdRequest,
+ CreateByConversationIdResponse,
+ GetEventsByParticipantIdResponse,
GetEventsResponse,
CreateByParticipantIdRequest,
CreateByParticipantIdResponse,
@@ -43,38 +43,36 @@ def __init__(self, client: Client):
self.client = client
- def get_events_by_participant_id(
+ def get_events_by_conversation_id(
self,
- participant_id: Any,
+ id: Any,
max_results: int = None,
pagination_token: Any = None,
event_types: List = None,
- dm_eventfields: List = None,
+ dm_event_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- userfields: List = None,
- tweetfields: List = None,
- ) -> GetEventsByParticipantIdResponse:
+ media_fields: List = None,
+ user_fields: List = None,
+ tweet_fields: List = None,
+ ) -> GetEventsByConversationIdResponse:
"""
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.
+ id: The DM conversation ID.
max_results: The maximum number of results.
pagination_token: This parameter is used to get a specified 'page' of results.
event_types: The set of event_types to include in the results.
- dm_eventfields: A comma separated list of DmEvent fields to display.
+ dm_event_fields: A comma separated list of DmEvent fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- userfields: A comma separated list of User fields to display.
- tweetfields: A comma separated list of Tweet fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ user_fields: A comma separated list of User fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
Returns:
- GetEventsByParticipantIdResponse: Response data
+ GetEventsByConversationIdResponse: Response data
"""
- url = (
- self.client.base_url + "/2/dm_conversations/with/{participant_id}/dm_events"
- )
- url = url.replace("{participant_id}", str(participant_id))
+ url = self.client.base_url + "/2/dm_conversations/{id}/dm_events"
+ url = url.replace("{id}", str(id))
# Ensure we have a valid access token
if self.client.oauth2_auth and self.client.token:
# Check if token needs refresh
@@ -87,16 +85,16 @@ def get_events_by_participant_id(
params["pagination_token"] = pagination_token
if event_types is not None:
params["event_types"] = ",".join(str(item) for item in event_types)
- if dm_eventfields is not None:
- params["dm_event.fields"] = ",".join(str(item) for item in dm_eventfields)
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 = {}
# Prepare request data
json_data = None
@@ -118,7 +116,57 @@ def get_events_by_participant_id(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetEventsByParticipantIdResponse.model_validate(response_data)
+ return GetEventsByConversationIdResponse.model_validate(response_data)
+
+
+ def create_conversation(
+ self, body: Optional[CreateConversationRequest] = None
+ ) -> Dict[str, Any]:
+ """
+ Create DM conversation
+ Initiates a new direct message conversation with specified participants.
+ body: Request body
+ Returns:
+ CreateConversationResponse: 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"
+ # Prepare request data
+ json_data = None
+ if body is not None:
+ json_data = (
+ body.model_dump(exclude_none=True)
+ if hasattr(body, "model_dump")
+ else body
+ )
+ # Make the request
+ if self.client.oauth2_session:
+ response = self.client.oauth2_session.post(
+ url,
+ params=params,
+ headers=headers,
+ json=json_data,
+ )
+ else:
+ response = self.client.session.post(
+ url,
+ params=params,
+ headers=headers,
+ json=json_data,
+ )
+ # Check for errors
+ response.raise_for_status()
+ # Parse the response data
+ response_data = response.json()
+ # Convert to Pydantic model if applicable
+ return CreateConversationResponse.model_validate(response_data)
def create_by_conversation_id(
@@ -176,36 +224,38 @@ def create_by_conversation_id(
return CreateByConversationIdResponse.model_validate(response_data)
- def get_events_by_conversation_id(
+ def get_events_by_participant_id(
self,
- id: Any,
+ participant_id: Any,
max_results: int = None,
pagination_token: Any = None,
event_types: List = None,
- dm_eventfields: List = None,
+ dm_event_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- userfields: List = None,
- tweetfields: List = None,
- ) -> GetEventsByConversationIdResponse:
+ media_fields: List = None,
+ user_fields: List = None,
+ tweet_fields: List = None,
+ ) -> GetEventsByParticipantIdResponse:
"""
Get DM events for a DM conversation
Retrieves direct message events for a specific conversation.
Args:
- id: The DM conversation ID.
+ participant_id: The ID of the participant user for the One to One DM conversation.
max_results: The maximum number of results.
pagination_token: This parameter is used to get a specified 'page' of results.
event_types: The set of event_types to include in the results.
- dm_eventfields: A comma separated list of DmEvent fields to display.
+ dm_event_fields: A comma separated list of DmEvent fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- userfields: A comma separated list of User fields to display.
- tweetfields: A comma separated list of Tweet fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ user_fields: A comma separated list of User fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
Returns:
- GetEventsByConversationIdResponse: Response data
+ GetEventsByParticipantIdResponse: Response data
"""
- url = self.client.base_url + "/2/dm_conversations/{id}/dm_events"
- url = url.replace("{id}", str(id))
+ url = (
+ self.client.base_url + "/2/dm_conversations/with/{participant_id}/dm_events"
+ )
+ url = url.replace("{participant_id}", str(participant_id))
# Ensure we have a valid access token
if self.client.oauth2_auth and self.client.token:
# Check if token needs refresh
@@ -218,16 +268,16 @@ def get_events_by_conversation_id(
params["pagination_token"] = pagination_token
if event_types is not None:
params["event_types"] = ",".join(str(item) for item in event_types)
- if dm_eventfields is not None:
- params["dm_event.fields"] = ",".join(str(item) for item in dm_eventfields)
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 = {}
# Prepare request data
json_data = None
@@ -249,57 +299,7 @@ def get_events_by_conversation_id(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetEventsByConversationIdResponse.model_validate(response_data)
-
-
- def create_conversation(
- self, body: Optional[CreateConversationRequest] = None
- ) -> Dict[str, Any]:
- """
- Create DM conversation
- Initiates a new direct message conversation with specified participants.
- body: Request body
- Returns:
- CreateConversationResponse: 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"
- # Prepare request data
- json_data = None
- if body is not None:
- json_data = (
- body.model_dump(exclude_none=True)
- if hasattr(body, "model_dump")
- else body
- )
- # Make the request
- if self.client.oauth2_session:
- response = self.client.oauth2_session.post(
- url,
- params=params,
- headers=headers,
- json=json_data,
- )
- else:
- response = self.client.session.post(
- url,
- params=params,
- headers=headers,
- json=json_data,
- )
- # Check for errors
- response.raise_for_status()
- # Parse the response data
- response_data = response.json()
- # Convert to Pydantic model if applicable
- return CreateConversationResponse.model_validate(response_data)
+ return GetEventsByParticipantIdResponse.model_validate(response_data)
def get_events(
@@ -307,11 +307,11 @@ def get_events(
max_results: int = None,
pagination_token: Any = None,
event_types: List = None,
- dm_eventfields: List = None,
+ dm_event_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- userfields: List = None,
- tweetfields: List = None,
+ media_fields: List = None,
+ user_fields: List = None,
+ tweet_fields: List = None,
) -> GetEventsResponse:
"""
Get DM events
@@ -320,11 +320,11 @@ def get_events(
max_results: The maximum number of results.
pagination_token: This parameter is used to get a specified 'page' of results.
event_types: The set of event_types to include in the results.
- dm_eventfields: A comma separated list of DmEvent fields to display.
+ dm_event_fields: A comma separated list of DmEvent fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- userfields: A comma separated list of User fields to display.
- tweetfields: A comma separated list of Tweet fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ user_fields: A comma separated list of User fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
Returns:
GetEventsResponse: Response data
"""
@@ -341,16 +341,16 @@ def get_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_eventfields is not None:
- params["dm_event.fields"] = ",".join(str(item) for item in dm_eventfields)
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 = {}
# Prepare request data
json_data = None
@@ -433,22 +433,22 @@ def create_by_participant_id(
def get_events_by_id(
self,
event_id: Any,
- dm_eventfields: List = None,
+ dm_event_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- userfields: List = None,
- tweetfields: List = None,
+ media_fields: List = None,
+ user_fields: List = None,
+ tweet_fields: List = None,
) -> GetEventsByIdResponse:
"""
Get DM event by ID
Retrieves details of a specific direct message event by its ID.
Args:
event_id: dm event id.
- dm_eventfields: A comma separated list of DmEvent fields to display.
+ dm_event_fields: A comma separated list of DmEvent fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- userfields: A comma separated list of User fields to display.
- tweetfields: A comma separated list of Tweet fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ user_fields: A comma separated list of User fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
Returns:
GetEventsByIdResponse: Response data
"""
@@ -460,16 +460,16 @@ def get_events_by_id(
if self.client.is_token_expired():
self.client.refresh_token()
params = {}
- if dm_eventfields is not None:
- params["dm_event.fields"] = ",".join(str(item) for item in dm_eventfields)
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 = {}
# Prepare request data
json_data = None
diff --git a/xdk/python/xdk/direct_messages/models.py b/xdk/python/xdk/direct_messages/models.py
index 96791b5c..5b2c5caf 100644
--- a/xdk/python/xdk/direct_messages/models.py
+++ b/xdk/python/xdk/direct_messages/models.py
@@ -16,50 +16,50 @@
from datetime import datetime
-# Models for get_events_by_participant_id
+# Models for get_events_by_conversation_id
-class GetEventsByParticipantIdResponse(BaseModel):
- """Response model for get_events_by_participant_id"""
+class GetEventsByConversationIdResponse(BaseModel):
+ """Response model for get_events_by_conversation_id"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for create_by_conversation_id
+# Models for create_conversation
-class CreateByConversationIdRequest(BaseModel):
- """Request model for create_by_conversation_id"""
+class CreateConversationRequest(BaseModel):
+ """Request model for create_conversation"""
model_config = ConfigDict(populate_by_name=True)
-class CreateByConversationIdResponse(BaseModel):
- """Response model for create_by_conversation_id"""
+class CreateConversationResponse(BaseModel):
+ """Response model for create_conversation"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_events_by_conversation_id
+# Models for create_by_conversation_id
-class GetEventsByConversationIdResponse(BaseModel):
- """Response model for get_events_by_conversation_id"""
+class CreateByConversationIdRequest(BaseModel):
+ """Request model for create_by_conversation_id"""
- model_config = ConfigDict(populate_by_name=True, extra="allow")
+ model_config = ConfigDict(populate_by_name=True)
-# Models for create_conversation
+class CreateByConversationIdResponse(BaseModel):
+ """Response model for create_by_conversation_id"""
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
-class CreateConversationRequest(BaseModel):
- """Request model for create_conversation"""
- model_config = ConfigDict(populate_by_name=True)
+# Models for get_events_by_participant_id
-class CreateConversationResponse(BaseModel):
- """Response model for create_conversation"""
+class GetEventsByParticipantIdResponse(BaseModel):
+ """Response model for get_events_by_participant_id"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
diff --git a/xdk/python/xdk/lists/client.py b/xdk/python/xdk/lists/client.py
index b4bff1f7..e04ab3e2 100644
--- a/xdk/python/xdk/lists/client.py
+++ b/xdk/python/xdk/lists/client.py
@@ -21,18 +21,18 @@
if TYPE_CHECKING:
from ..client import Client
from .models import (
- GetFollowersResponse,
- GetMembersResponse,
- AddMemberRequest,
- AddMemberResponse,
- GetPostsResponse,
CreateRequest,
CreateResponse,
- RemoveMemberByUserIdResponse,
GetByIdResponse,
UpdateRequest,
UpdateResponse,
DeleteResponse,
+ GetFollowersResponse,
+ RemoveMemberByUserIdResponse,
+ GetPostsResponse,
+ GetMembersResponse,
+ AddMemberRequest,
+ AddMemberResponse,
)
@@ -44,94 +44,73 @@ def __init__(self, client: Client):
self.client = client
- def get_followers(
- self,
- id: Any,
- max_results: int = None,
- pagination_token: Any = None,
- userfields: List = None,
- expansions: List = None,
- tweetfields: List = None,
- ) -> GetFollowersResponse:
+ def create(self, body: Optional[CreateRequest] = None) -> CreateResponse:
"""
- Get List followers
- Retrieves a list of Users who follow a specific List by its ID.
- Args:
- id: The ID of the List.
- max_results: The maximum number of results.
- pagination_token: This parameter is used to get a specified 'page' of results.
- userfields: A comma separated list of User fields to display.
- expansions: A comma separated list of fields to expand.
- tweetfields: A comma separated list of Tweet fields to display.
- Returns:
- GetFollowersResponse: Response data
+ Create List
+ Creates a new List for the authenticated user.
+ body: Request body
+ Returns:
+ CreateResponse: Response data
"""
- url = self.client.base_url + "/2/lists/{id}/followers"
- url = url.replace("{id}", str(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}"
- )
+ 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 = {}
- if max_results is not None:
- params["max_results"] = max_results
- if pagination_token is not None:
- params["pagination_token"] = pagination_token
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if expansions is not None:
- params["expansions"] = ",".join(str(item) for item in expansions)
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
headers = {}
+ headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
+ if body is not None:
+ json_data = (
+ body.model_dump(exclude_none=True)
+ if hasattr(body, "model_dump")
+ else body
+ )
# 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=json_data,
+ )
+ else:
+ response = self.client.session.post(
+ url,
+ params=params,
+ headers=headers,
+ json=json_data,
+ )
# 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)
+ return CreateResponse.model_validate(response_data)
- def get_members(
+ def get_by_id(
self,
id: Any,
- max_results: int = None,
- pagination_token: Any = None,
- userfields: List = None,
+ list_fields: List = None,
expansions: List = None,
- tweetfields: List = None,
- ) -> GetMembersResponse:
+ user_fields: List = None,
+ ) -> GetByIdResponse:
"""
- Get List members
- Retrieves a list of Users who are members of a specific List by its ID.
+ Get List by ID
+ Retrieves details of a specific List by its ID.
Args:
id: The ID of the List.
- max_results: The maximum number of results.
- pagination_token: This parameter is used to get a specified 'page' of results.
- userfields: A comma separated list of User fields to display.
+ list_fields: A comma separated list of List fields to display.
expansions: A comma separated list of fields to expand.
- tweetfields: A comma separated list of Tweet fields to display.
+ user_fields: A comma separated list of User fields to display.
Returns:
- GetMembersResponse: Response data
+ GetByIdResponse: Response data
"""
- url = self.client.base_url + "/2/lists/{id}/members"
+ url = self.client.base_url + "/2/lists/{id}"
url = url.replace("{id}", str(id))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
@@ -147,16 +126,12 @@ def get_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 userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
+ 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 tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ if user_fields is not None:
+ params["user.fields"] = ",".join(str(item) for item in user_fields)
headers = {}
# Prepare request data
json_data = None
@@ -171,22 +146,20 @@ def get_members(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetMembersResponse.model_validate(response_data)
+ return GetByIdResponse.model_validate(response_data)
- def add_member(
- self, id: Any, body: Optional[AddMemberRequest] = None
- ) -> AddMemberResponse:
+ def update(self, id: Any, body: Optional[UpdateRequest] = None) -> UpdateResponse:
"""
- Add List member
- Adds a User to a specific List by its ID.
+ Update List
+ Updates the details of a specific List owned by the authenticated user by its ID.
Args:
- id: The ID of the List for which to add a member.
+ id: The ID of the List to modify.
body: Request body
Returns:
- AddMemberResponse: Response data
+ UpdateResponse: Response data
"""
- url = self.client.base_url + "/2/lists/{id}/members"
+ url = self.client.base_url + "/2/lists/{id}"
url = url.replace("{id}", str(id))
# Ensure we have a valid access token
if self.client.oauth2_auth and self.client.token:
@@ -206,14 +179,14 @@ def add_member(
)
# Make the request
if self.client.oauth2_session:
- response = self.client.oauth2_session.post(
+ response = self.client.oauth2_session.put(
url,
params=params,
headers=headers,
json=json_data,
)
else:
- response = self.client.session.post(
+ response = self.client.session.put(
url,
params=params,
headers=headers,
@@ -224,38 +197,73 @@ def add_member(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return AddMemberResponse.model_validate(response_data)
+ return UpdateResponse.model_validate(response_data)
- def get_posts(
+ def delete(self, 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:
+ DeleteResponse: Response data
+ """
+ url = self.client.base_url + "/2/lists/{id}"
+ url = url.replace("{id}", str(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 = {}
+ headers = {}
+ # Prepare request data
+ json_data = None
+ # 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_followers(
self,
id: Any,
max_results: int = None,
pagination_token: Any = None,
- tweetfields: List = None,
+ user_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
- ) -> GetPostsResponse:
+ tweet_fields: List = None,
+ ) -> GetFollowersResponse:
"""
- Get List Posts
- Retrieves a list of Posts associated with 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 List.
max_results: The maximum number of results.
- pagination_token: This parameter is used to get the next 'page' of results.
- tweetfields: A comma separated list of Tweet fields to display.
+ pagination_token: This parameter is used to get a specified 'page' of results.
+ user_fields: A comma separated list of User fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
Returns:
- GetPostsResponse: Response data
+ GetFollowersResponse: Response data
"""
- url = self.client.base_url + "/2/lists/{id}/tweets"
+ url = self.client.base_url + "/2/lists/{id}/followers"
url = url.replace("{id}", str(id))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
@@ -275,18 +283,12 @@ def get_posts(
params["max_results"] = max_results
if pagination_token is not None:
params["pagination_token"] = pagination_token
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
+ if tweet_fields is not None:
+ params["tweet.fields"] = ",".join(str(item) for item in tweet_fields)
headers = {}
# Prepare request data
json_data = None
@@ -301,55 +303,7 @@ def get_posts(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetPostsResponse.model_validate(response_data)
-
-
- def create(self, body: Optional[CreateRequest] = None) -> CreateResponse:
- """
- Create List
- Creates a new List for the authenticated user.
- body: Request body
- Returns:
- CreateResponse: 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"
- # Prepare request data
- json_data = None
- if body is not None:
- json_data = (
- body.model_dump(exclude_none=True)
- if hasattr(body, "model_dump")
- else body
- )
- # Make the request
- if self.client.oauth2_session:
- response = self.client.oauth2_session.post(
- url,
- params=params,
- headers=headers,
- json=json_data,
- )
- else:
- response = self.client.session.post(
- url,
- params=params,
- headers=headers,
- json=json_data,
- )
- # 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)
+ return GetFollowersResponse.model_validate(response_data)
def remove_member_by_user_id(
@@ -397,25 +351,35 @@ def remove_member_by_user_id(
return RemoveMemberByUserIdResponse.model_validate(response_data)
- def get_by_id(
+ def get_posts(
self,
id: Any,
- listfields: List = None,
+ max_results: int = None,
+ pagination_token: Any = None,
+ tweet_fields: List = None,
expansions: List = None,
- userfields: List = None,
- ) -> GetByIdResponse:
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
+ ) -> GetPostsResponse:
"""
- Get List by ID
- Retrieves details of a specific List by its ID.
+ Get List Posts
+ Retrieves a list of Posts associated with a specific List by its ID.
Args:
id: The ID of the List.
- listfields: A comma separated list of List fields to display.
+ max_results: The maximum number of results.
+ pagination_token: This parameter is used to get the next 'page' of results.
+ tweet_fields: A comma separated list of Tweet fields to display.
expansions: A comma separated list of fields to expand.
- userfields: A comma separated list of User fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
Returns:
- GetByIdResponse: Response data
+ GetPostsResponse: Response data
"""
- url = self.client.base_url + "/2/lists/{id}"
+ url = self.client.base_url + "/2/lists/{id}/tweets"
url = url.replace("{id}", str(id))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
@@ -431,12 +395,22 @@ def get_by_id(
if self.client.is_token_expired():
self.client.refresh_token()
params = {}
- if listfields is not None:
- params["list.fields"] = ",".join(str(item) for item in listfields)
+ 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 userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
+ 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 = {}
# Prepare request data
json_data = None
@@ -451,70 +425,87 @@ def get_by_id(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetByIdResponse.model_validate(response_data)
+ return GetPostsResponse.model_validate(response_data)
- def update(self, id: Any, body: Optional[UpdateRequest] = None) -> UpdateResponse:
+ def get_members(
+ self,
+ id: Any,
+ max_results: int = None,
+ pagination_token: Any = None,
+ user_fields: List = None,
+ expansions: List = None,
+ tweet_fields: List = None,
+ ) -> GetMembersResponse:
"""
- Update List
- Updates the details of a specific List owned by the authenticated user by its ID.
+ 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 to modify.
- body: Request body
- Returns:
- UpdateResponse: Response data
+ id: The ID of the List.
+ max_results: The maximum number of results.
+ pagination_token: This parameter is used to get a specified 'page' of results.
+ user_fields: A comma separated list of User fields to display.
+ expansions: A comma separated list of fields to expand.
+ tweet_fields: A comma separated list of Tweet fields to display.
+ Returns:
+ GetMembersResponse: Response data
"""
- url = self.client.base_url + "/2/lists/{id}"
+ url = self.client.base_url + "/2/lists/{id}/members"
url = url.replace("{id}", str(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 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)
headers = {}
- headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
- if body is not None:
- json_data = (
- body.model_dump(exclude_none=True)
- if hasattr(body, "model_dump")
- else body
- )
# Make the request
- if self.client.oauth2_session:
- response = self.client.oauth2_session.put(
- url,
- params=params,
- headers=headers,
- json=json_data,
- )
- else:
- response = self.client.session.put(
- url,
- params=params,
- headers=headers,
- json=json_data,
- )
+ 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 UpdateResponse.model_validate(response_data)
+ return GetMembersResponse.model_validate(response_data)
- def delete(self, id: Any) -> DeleteResponse:
+ def add_member(
+ self, id: Any, body: Optional[AddMemberRequest] = None
+ ) -> AddMemberResponse:
"""
- Delete List
- Deletes a specific List owned by the authenticated user by its ID.
+ Add List member
+ Adds a User to a specific List by its ID.
Args:
- id: The ID of the List to delete.
- Returns:
- DeleteResponse: Response data
+ id: The ID of the List for which to add a member.
+ body: Request body
+ Returns:
+ AddMemberResponse: Response data
"""
- url = self.client.base_url + "/2/lists/{id}"
+ url = self.client.base_url + "/2/lists/{id}/members"
url = url.replace("{id}", str(id))
# Ensure we have a valid access token
if self.client.oauth2_auth and self.client.token:
@@ -523,24 +514,33 @@ def delete(self, id: Any) -> DeleteResponse:
self.client.refresh_token()
params = {}
headers = {}
+ headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
+ if body is not None:
+ json_data = (
+ body.model_dump(exclude_none=True)
+ if hasattr(body, "model_dump")
+ else body
+ )
# 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=json_data,
)
else:
- response = self.client.session.delete(
+ response = self.client.session.post(
url,
params=params,
headers=headers,
+ json=json_data,
)
# 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)
+ return AddMemberResponse.model_validate(response_data)
diff --git a/xdk/python/xdk/lists/models.py b/xdk/python/xdk/lists/models.py
index d9f86e40..3978e2da 100644
--- a/xdk/python/xdk/lists/models.py
+++ b/xdk/python/xdk/lists/models.py
@@ -16,59 +16,59 @@
from datetime import datetime
-# Models for get_followers
+# Models for create
-class GetFollowersResponse(BaseModel):
- """Response model for get_followers"""
+class CreateRequest(BaseModel):
+ """Request model for create"""
+
+ model_config = ConfigDict(populate_by_name=True)
+
+
+class CreateResponse(BaseModel):
+ """Response model for create"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_members
+# Models for get_by_id
-class GetMembersResponse(BaseModel):
- """Response model for get_members"""
+class GetByIdResponse(BaseModel):
+ """Response model for get_by_id"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for add_member
+# Models for update
-class AddMemberRequest(BaseModel):
- """Request model for add_member"""
+class UpdateRequest(BaseModel):
+ """Request model for update"""
model_config = ConfigDict(populate_by_name=True)
-class AddMemberResponse(BaseModel):
- """Response model for add_member"""
+class UpdateResponse(BaseModel):
+ """Response model for update"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_posts
+# Models for delete
-class GetPostsResponse(BaseModel):
- """Response model for get_posts"""
+class DeleteResponse(BaseModel):
+ """Response model for delete"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for create
-
-
-class CreateRequest(BaseModel):
- """Request model for create"""
-
- model_config = ConfigDict(populate_by_name=True)
+# Models for get_followers
-class CreateResponse(BaseModel):
- """Response model for create"""
+class GetFollowersResponse(BaseModel):
+ """Response model for get_followers"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
@@ -82,34 +82,34 @@ class RemoveMemberByUserIdResponse(BaseModel):
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_by_id
+# Models for get_posts
-class GetByIdResponse(BaseModel):
- """Response model for get_by_id"""
+class GetPostsResponse(BaseModel):
+ """Response model for get_posts"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for update
+# Models for get_members
-class UpdateRequest(BaseModel):
- """Request model for update"""
+class GetMembersResponse(BaseModel):
+ """Response model for get_members"""
- model_config = ConfigDict(populate_by_name=True)
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
-class UpdateResponse(BaseModel):
- """Response model for update"""
+# Models for add_member
- model_config = ConfigDict(populate_by_name=True, extra="allow")
+class AddMemberRequest(BaseModel):
+ """Request model for add_member"""
-# Models for delete
+ model_config = ConfigDict(populate_by_name=True)
-class DeleteResponse(BaseModel):
- """Response model for delete"""
+class AddMemberResponse(BaseModel):
+ """Response model for add_member"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
diff --git a/xdk/python/xdk/media/client.py b/xdk/python/xdk/media/client.py
index e386b4dd..216464e4 100644
--- a/xdk/python/xdk/media/client.py
+++ b/xdk/python/xdk/media/client.py
@@ -21,23 +21,23 @@
if TYPE_CHECKING:
from ..client import Client
from .models import (
+ GetUploadStatusResponse,
+ UploadRequest,
+ UploadResponse,
CreateSubtitlesRequest,
CreateSubtitlesResponse,
DeleteSubtitlesRequest,
DeleteSubtitlesResponse,
- GetAnalyticsResponse,
+ InitializeUploadRequest,
+ InitializeUploadResponse,
GetByKeysResponse,
- GetByKeyResponse,
- FinalizeUploadResponse,
AppendUploadRequest,
AppendUploadResponse,
- InitializeUploadRequest,
- InitializeUploadResponse,
CreateMetadataRequest,
CreateMetadataResponse,
- GetUploadStatusResponse,
- UploadRequest,
- UploadResponse,
+ FinalizeUploadResponse,
+ GetByKeyResponse,
+ GetAnalyticsResponse,
)
@@ -49,6 +49,101 @@ def __init__(self, client: Client):
self.client = client
+ def get_upload_status(
+ self, media_id: Any, command: str = None
+ ) -> GetUploadStatusResponse:
+ """
+ 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.
+ command: The command for the media upload request.
+ Returns:
+ GetUploadStatusResponse: 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 = {}
+ # Prepare request data
+ json_data = None
+ # 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 GetUploadStatusResponse.model_validate(response_data)
+
+
+ def upload(self, body: Optional[UploadRequest] = None) -> UploadResponse:
+ """
+ Upload media
+ Uploads a media file for use in posts or other content.
+ body: Request body
+ Returns:
+ UploadResponse: 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"
+ # Prepare request data
+ json_data = None
+ if body is not None:
+ json_data = (
+ body.model_dump(exclude_none=True)
+ if hasattr(body, "model_dump")
+ else body
+ )
+ # Make the request
+ if self.client.oauth2_session:
+ response = self.client.oauth2_session.post(
+ url,
+ params=params,
+ headers=headers,
+ json=json_data,
+ )
+ else:
+ response = self.client.session.post(
+ url,
+ params=params,
+ headers=headers,
+ json=json_data,
+ )
+ # Check for errors
+ response.raise_for_status()
+ # Parse the response data
+ response_data = response.json()
+ # Convert to Pydantic model if applicable
+ return UploadResponse.model_validate(response_data)
+
+
def create_subtitles(
self, body: Optional[CreateSubtitlesRequest] = None
) -> CreateSubtitlesResponse:
@@ -149,78 +244,65 @@ def delete_subtitles(
return DeleteSubtitlesResponse.model_validate(response_data)
- def get_analytics(
- self,
- media_keys: List,
- end_time: str,
- start_time: str,
- granularity: str,
- media_analyticsfields: List = None,
- ) -> GetAnalyticsResponse:
+ def initialize_upload(
+ self, body: Optional[InitializeUploadRequest] = None
+ ) -> InitializeUploadResponse:
"""
- 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.
- end_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range.
- start_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range.
- granularity: The granularity for the search counts results.
- media_analyticsfields: A comma separated list of MediaAnalytics fields to display.
- Returns:
- GetAnalyticsResponse: Response data
+ Initialize media upload
+ Initializes a media upload.
+ body: Request body
+ Returns:
+ InitializeUploadResponse: Response data
"""
- url = self.client.base_url + "/2/media/analytics"
+ 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 = {}
- 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_analyticsfields is not None:
- params["media_analytics.fields"] = ",".join(
- str(item) for item in media_analyticsfields
- )
headers = {}
+ headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
+ if body is not None:
+ json_data = (
+ body.model_dump(exclude_none=True)
+ if hasattr(body, "model_dump")
+ else body
+ )
# 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=json_data,
)
else:
- response = self.client.session.get(
+ response = self.client.session.post(
url,
params=params,
headers=headers,
+ json=json_data,
)
# 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)
+ return InitializeUploadResponse.model_validate(response_data)
def get_by_keys(
- self, media_keys: List, mediafields: List = None
+ self, media_keys: List, media_fields: List = None
) -> GetByKeysResponse:
"""
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.
- mediafields: A comma separated list of Media fields to display.
+ media_fields: A comma separated list of Media fields to display.
Returns:
GetByKeysResponse: Response data
"""
@@ -241,8 +323,8 @@ def get_by_keys(
params = {}
if media_keys is not None:
params["media_keys"] = ",".join(str(item) for item in media_keys)
- if mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
+ if media_fields is not None:
+ params["media.fields"] = ",".join(str(item) for item in media_fields)
headers = {}
# Prepare request data
json_data = None
@@ -260,92 +342,6 @@ def get_by_keys(
return GetByKeysResponse.model_validate(response_data)
- def get_by_key(self, media_key: Any, mediafields: List = None) -> GetByKeyResponse:
- """
- Get Media by media key
- Retrieves details of a specific Media file by its media key.
- Args:
- media_key: A single Media Key.
- mediafields: A comma separated list of Media fields to display.
- Returns:
- GetByKeyResponse: Response data
- """
- url = self.client.base_url + "/2/media/{media_key}"
- url = url.replace("{media_key}", str(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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- headers = {}
- # Prepare request data
- json_data = None
- # 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 GetByKeyResponse.model_validate(response_data)
-
-
- def finalize_upload(self, id: Any) -> FinalizeUploadResponse:
- """
- Finalize Media upload
- Finalizes a Media upload request.
- Args:
- id: The media id of the targeted media to finalize.
- Returns:
- FinalizeUploadResponse: Response data
- """
- url = self.client.base_url + "/2/media/upload/{id}/finalize"
- url = url.replace("{id}", str(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 = {}
- headers = {}
- # Prepare request data
- json_data = None
- # 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 FinalizeUploadResponse.model_validate(response_data)
-
-
def append_upload(
self, id: Any, body: Optional[AppendUploadRequest] = None
) -> AppendUploadResponse:
@@ -399,17 +395,17 @@ def append_upload(
return AppendUploadResponse.model_validate(response_data)
- def initialize_upload(
- self, body: Optional[InitializeUploadRequest] = None
- ) -> InitializeUploadResponse:
+ def create_metadata(
+ self, body: Optional[CreateMetadataRequest] = None
+ ) -> CreateMetadataResponse:
"""
- Initialize media upload
- Initializes a media upload.
+ Create Media metadata
+ Creates metadata for a Media file.
body: Request body
Returns:
- InitializeUploadResponse: Response data
+ CreateMetadataResponse: Response data
"""
- url = self.client.base_url + "/2/media/upload/initialize"
+ 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
@@ -446,20 +442,20 @@ def initialize_upload(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return InitializeUploadResponse.model_validate(response_data)
+ return CreateMetadataResponse.model_validate(response_data)
- def create_metadata(
- self, body: Optional[CreateMetadataRequest] = None
- ) -> CreateMetadataResponse:
+ def finalize_upload(self, id: Any) -> FinalizeUploadResponse:
"""
- Create Media metadata
- Creates metadata for a Media file.
- body: Request body
- Returns:
- CreateMetadataResponse: Response data
+ Finalize Media upload
+ Finalizes a Media upload request.
+ Args:
+ id: The media id of the targeted media to finalize.
+ Returns:
+ FinalizeUploadResponse: Response data
"""
- url = self.client.base_url + "/2/media/metadata"
+ url = self.client.base_url + "/2/media/upload/{id}/finalize"
+ url = url.replace("{id}", str(id))
# Ensure we have a valid access token
if self.client.oauth2_auth and self.client.token:
# Check if token needs refresh
@@ -467,128 +463,132 @@ def create_metadata(
self.client.refresh_token()
params = {}
headers = {}
- headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
- if body is not None:
- json_data = (
- body.model_dump(exclude_none=True)
- if hasattr(body, "model_dump")
- else body
- )
# Make the request
if self.client.oauth2_session:
response = self.client.oauth2_session.post(
url,
params=params,
headers=headers,
- json=json_data,
)
else:
response = self.client.session.post(
url,
params=params,
headers=headers,
- json=json_data,
)
# Check for errors
response.raise_for_status()
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return CreateMetadataResponse.model_validate(response_data)
+ return FinalizeUploadResponse.model_validate(response_data)
- def get_upload_status(
- self, media_id: Any, command: str = None
- ) -> GetUploadStatusResponse:
+ def get_by_key(self, media_key: Any, media_fields: List = None) -> GetByKeyResponse:
"""
- Get Media upload status
- Retrieves the status of a Media upload by its ID.
+ Get Media by media key
+ Retrieves details of a specific Media file by its media key.
Args:
- media_id: Media id for the requested media upload status.
- command: The command for the media upload request.
+ media_key: A single Media Key.
+ media_fields: A comma separated list of Media fields to display.
Returns:
- GetUploadStatusResponse: Response data
+ GetByKeyResponse: Response data
"""
- url = self.client.base_url + "/2/media/upload"
+ url = self.client.base_url + "/2/media/{media_key}"
+ url = url.replace("{media_key}", str(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_id is not None:
- params["media_id"] = media_id
- if command is not None:
- params["command"] = command
+ if media_fields is not None:
+ params["media.fields"] = ",".join(str(item) for item in media_fields)
headers = {}
# Prepare request data
json_data = None
# 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 GetUploadStatusResponse.model_validate(response_data)
+ return GetByKeyResponse.model_validate(response_data)
- def upload(self, body: Optional[UploadRequest] = None) -> UploadResponse:
+ def get_analytics(
+ self,
+ media_keys: List,
+ end_time: str,
+ start_time: str,
+ granularity: str,
+ media_analytics_fields: List = None,
+ ) -> GetAnalyticsResponse:
"""
- Upload media
- Uploads a media file for use in posts or other content.
- body: Request body
- Returns:
- UploadResponse: Response data
+ 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.
+ end_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range.
+ start_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range.
+ granularity: The granularity for the search counts results.
+ media_analytics_fields: A comma separated list of MediaAnalytics fields to display.
+ Returns:
+ GetAnalyticsResponse: Response data
"""
- url = self.client.base_url + "/2/media/upload"
+ 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 = {}
- headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
- if body is not None:
- json_data = (
- body.model_dump(exclude_none=True)
- if hasattr(body, "model_dump")
- else body
- )
# 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=json_data,
)
else:
- response = self.client.session.post(
+ response = self.client.session.get(
url,
params=params,
headers=headers,
- json=json_data,
)
# Check for errors
response.raise_for_status()
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return UploadResponse.model_validate(response_data)
+ return GetAnalyticsResponse.model_validate(response_data)
diff --git a/xdk/python/xdk/media/models.py b/xdk/python/xdk/media/models.py
index 59744870..943fb6a7 100644
--- a/xdk/python/xdk/media/models.py
+++ b/xdk/python/xdk/media/models.py
@@ -16,6 +16,30 @@
from datetime import datetime
+# Models for get_upload_status
+
+
+class GetUploadStatusResponse(BaseModel):
+ """Response model for get_upload_status"""
+
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
+
+
+# Models for upload
+
+
+class UploadRequest(BaseModel):
+ """Request model for upload"""
+
+ model_config = ConfigDict(populate_by_name=True)
+
+
+class UploadResponse(BaseModel):
+ """Response model for upload"""
+
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
+
+
# Models for create_subtitles
@@ -46,38 +70,26 @@ class DeleteSubtitlesResponse(BaseModel):
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_analytics
-
-
-class GetAnalyticsResponse(BaseModel):
- """Response model for get_analytics"""
-
- model_config = ConfigDict(populate_by_name=True, extra="allow")
-
-
-# Models for get_by_keys
-
-
-class GetByKeysResponse(BaseModel):
- """Response model for get_by_keys"""
+# Models for initialize_upload
- model_config = ConfigDict(populate_by_name=True, extra="allow")
+class InitializeUploadRequest(BaseModel):
+ """Request model for initialize_upload"""
-# Models for get_by_key
+ model_config = ConfigDict(populate_by_name=True)
-class GetByKeyResponse(BaseModel):
- """Response model for get_by_key"""
+class InitializeUploadResponse(BaseModel):
+ """Response model for initialize_upload"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for finalize_upload
+# Models for get_by_keys
-class FinalizeUploadResponse(BaseModel):
- """Response model for finalize_upload"""
+class GetByKeysResponse(BaseModel):
+ """Response model for get_by_keys"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
@@ -97,21 +109,6 @@ class AppendUploadResponse(BaseModel):
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for initialize_upload
-
-
-class InitializeUploadRequest(BaseModel):
- """Request model for initialize_upload"""
-
- model_config = ConfigDict(populate_by_name=True)
-
-
-class InitializeUploadResponse(BaseModel):
- """Response model for initialize_upload"""
-
- model_config = ConfigDict(populate_by_name=True, extra="allow")
-
-
# Models for create_metadata
@@ -127,25 +124,28 @@ class CreateMetadataResponse(BaseModel):
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_upload_status
+# Models for finalize_upload
-class GetUploadStatusResponse(BaseModel):
- """Response model for get_upload_status"""
+class FinalizeUploadResponse(BaseModel):
+ """Response model for finalize_upload"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for upload
+# Models for get_by_key
-class UploadRequest(BaseModel):
- """Request model for upload"""
+class GetByKeyResponse(BaseModel):
+ """Response model for get_by_key"""
- model_config = ConfigDict(populate_by_name=True)
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
-class UploadResponse(BaseModel):
- """Response model for upload"""
+# Models for get_analytics
+
+
+class GetAnalyticsResponse(BaseModel):
+ """Response model for get_analytics"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
diff --git a/xdk/python/xdk/news/__init__.py b/xdk/python/xdk/news/__init__.py
new file mode 100644
index 00000000..d8ed8770
--- /dev/null
+++ b/xdk/python/xdk/news/__init__.py
@@ -0,0 +1,15 @@
+# AUTO-GENERATED FILE - DO NOT EDIT
+# This file was automatically generated by the XDK build tool.
+# Any manual changes will be overwritten on the next generation.
+"""
+Auto-generated news module for the X API.
+
+This module provides access to the news endpoints of the X API
+and serves as the main entry point for all news-related functionality.
+
+Generated automatically - do not edit manually.
+"""
+
+from .client import NewsClient
+
+__all__ = ["NewsClient"]
diff --git a/xdk/python/xdk/news/client.py b/xdk/python/xdk/news/client.py
new file mode 100644
index 00000000..f717d7f4
--- /dev/null
+++ b/xdk/python/xdk/news/client.py
@@ -0,0 +1,137 @@
+# AUTO-GENERATED FILE - DO NOT EDIT
+# This file was automatically generated by the XDK build tool.
+# Any manual changes will be overwritten on the next generation.
+
+"""
+Auto-generated news client for the X API.
+
+This module provides a client for interacting with the news endpoints of the X API.
+
+All methods, parameters, and response models are generated from the OpenAPI specification.
+
+Generated automatically - do not edit manually.
+"""
+
+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 (
+ SearchResponse,
+ GetResponse,
+)
+
+
+class NewsClient:
+ """Client for news operations"""
+
+
+ def __init__(self, client: Client):
+ self.client = client
+
+
+ def search(
+ self,
+ query: str,
+ max_results: int = None,
+ max_age_hours: int = None,
+ news_fields: List = None,
+ ) -> SearchResponse:
+ """
+ Search News
+ Retrieves a list of News stories matching the specified search query.
+ Args:
+ query: The search query.
+ max_results: The number of results to return.
+ max_age_hours: The maximum age of the News story to search for.
+ news_fields: A comma separated list of News fields to display.
+ Returns:
+ SearchResponse: Response data
+ """
+ url = self.client.base_url + "/2/news/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 max_results is not None:
+ params["max_results"] = max_results
+ if max_age_hours is not None:
+ params["max_age_hours"] = max_age_hours
+ if news_fields is not None:
+ params["news.fields"] = ",".join(str(item) for item in news_fields)
+ headers = {}
+ # Prepare request data
+ json_data = None
+ # 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 SearchResponse.model_validate(response_data)
+
+
+ def get(self, id: Any, news_fields: List = None) -> GetResponse:
+ """
+ Get news stories by ID
+ Retrieves news story by its ID.
+ Args:
+ id: The ID of the news story.
+ news_fields: A comma separated list of News fields to display.
+ Returns:
+ GetResponse: Response data
+ """
+ url = self.client.base_url + "/2/news/{id}"
+ url = url.replace("{id}", str(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 news_fields is not None:
+ params["news.fields"] = ",".join(str(item) for item in news_fields)
+ headers = {}
+ # Prepare request data
+ json_data = None
+ # 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 GetResponse.model_validate(response_data)
diff --git a/xdk/python/xdk/news/models.py b/xdk/python/xdk/news/models.py
new file mode 100644
index 00000000..fb791956
--- /dev/null
+++ b/xdk/python/xdk/news/models.py
@@ -0,0 +1,34 @@
+# AUTO-GENERATED FILE - DO NOT EDIT
+# This file was automatically generated by the XDK build tool.
+# Any manual changes will be overwritten on the next generation.
+"""
+Auto-generated news models for the X API.
+
+This module provides Pydantic models for request and response data structures
+for the news endpoints of the X API. All models are generated
+from the OpenAPI specification and provide type safety and validation.
+
+Generated automatically - do not edit manually.
+"""
+
+from typing import Dict, List, Optional, Any, Union, Literal
+from pydantic import BaseModel, Field, ConfigDict
+from datetime import datetime
+
+
+# Models for search
+
+
+class SearchResponse(BaseModel):
+ """Response model for search"""
+
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
+
+
+# Models for get
+
+
+class GetResponse(BaseModel):
+ """Response model for get"""
+
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
diff --git a/xdk/python/xdk/posts/client.py b/xdk/python/xdk/posts/client.py
index e16518aa..6e9190e3 100644
--- a/xdk/python/xdk/posts/client.py
+++ b/xdk/python/xdk/posts/client.py
@@ -22,23 +22,23 @@
from ..client import Client
from .models import (
GetQuotedResponse,
- GetCountsAllResponse,
- GetByIdResponse,
- DeleteResponse,
- GetInsights28hrResponse,
- GetCountsRecentResponse,
- SearchAllResponse,
+ GetAnalyticsResponse,
+ HideReplyRequest,
+ HideReplyResponse,
GetRepostedByResponse,
- SearchRecentResponse,
- GetInsightsHistoricalResponse,
+ GetRepostsResponse,
GetByIdsResponse,
CreateRequest,
CreateResponse,
GetLikingUsersResponse,
- GetAnalyticsResponse,
- HideReplyRequest,
- HideReplyResponse,
- GetRepostsResponse,
+ GetCountsRecentResponse,
+ GetCountsAllResponse,
+ SearchAllResponse,
+ SearchRecentResponse,
+ GetInsightsHistoricalResponse,
+ GetByIdResponse,
+ DeleteResponse,
+ GetInsights28hrResponse,
)
@@ -56,12 +56,12 @@ def get_quoted(
max_results: int = None,
pagination_token: Any = None,
exclude: List = None,
- tweetfields: List = None,
+ tweet_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
) -> GetQuotedResponse:
"""
Get Quoted Posts
@@ -71,12 +71,12 @@ def get_quoted(
max_results: The maximum number of results to be returned.
pagination_token: This parameter is used to get a specified 'page' of results.
exclude: The set of entities to exclude (e.g. 'replies' or 'retweets').
- tweetfields: A comma separated list of Tweet fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
Returns:
GetQuotedResponse: Response data
"""
@@ -102,18 +102,18 @@ def get_quoted(
params["pagination_token"] = pagination_token
if exclude is not None:
params["exclude"] = ",".join(str(item) for item in exclude)
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
+ 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 = {}
# Prepare request data
json_data = None
@@ -131,35 +131,146 @@ def get_quoted(
return GetQuotedResponse.model_validate(response_data)
- def get_counts_all(
+ def get_analytics(
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,
- search_countfields: List = None,
- ) -> GetCountsAllResponse:
+ ids: List,
+ end_time: str,
+ start_time: str,
+ granularity: str,
+ analytics_fields: List = None,
+ ) -> GetAnalyticsResponse:
"""
- Get count of all Posts
- Retrieves the count of Posts matching a search query from the full archive.
+ Get Post analytics
+ Retrieves analytics data for specified Posts within a defined time range.
Args:
- query: One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length.
- 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).
- 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).
- since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID.
- until_id: Returns results with a Post ID less than (that is, older than) the specified ID.
- 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.
- 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.
+ ids: A comma separated list of Post IDs. Up to 100 are allowed in a single request.
+ end_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range.
+ start_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range.
granularity: The granularity for the search counts results.
- search_countfields: A comma separated list of SearchCount fields to display.
+ analytics_fields: A comma separated list of Analytics fields to display.
Returns:
- GetCountsAllResponse: Response data
+ GetAnalyticsResponse: Response data
"""
- url = self.client.base_url + "/2/tweets/counts/all"
+ 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 = {}
+ # Prepare request data
+ json_data = None
+ # 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 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"
+ url = url.replace("{tweet_id}", str(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 = {}
+ headers = {}
+ headers["Content-Type"] = "application/json"
+ # Prepare request data
+ json_data = None
+ if body is not None:
+ json_data = (
+ body.model_dump(exclude_none=True)
+ if hasattr(body, "model_dump")
+ else body
+ )
+ # Make the request
+ if self.client.oauth2_session:
+ response = self.client.oauth2_session.put(
+ url,
+ params=params,
+ headers=headers,
+ json=json_data,
+ )
+ else:
+ response = self.client.session.put(
+ url,
+ params=params,
+ headers=headers,
+ json=json_data,
+ )
+ # 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 get_reposted_by(
+ self,
+ id: Any,
+ max_results: int = None,
+ pagination_token: Any = None,
+ user_fields: List = None,
+ expansions: List = None,
+ tweet_fields: List = None,
+ ) -> GetRepostedByResponse:
+ """
+ Get Reposted by
+ Retrieves a list of Users who reposted a specific Post by its ID.
+ Args:
+ id: A single Post ID.
+ max_results: The maximum number of results.
+ pagination_token: This parameter is used to get the next 'page' of results.
+ user_fields: A comma separated list of User fields to display.
+ expansions: A comma separated list of fields to expand.
+ tweet_fields: A comma separated list of Tweet fields to display.
+ Returns:
+ GetRepostedByResponse: Response data
+ """
+ url = self.client.base_url + "/2/tweets/{id}/retweeted_by"
+ url = url.replace("{id}", str(id))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
f"Bearer {self.client.bearer_token}"
@@ -168,27 +279,22 @@ def get_counts_all(
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 next_token is not None:
- params["next_token"] = next_token
+ if max_results is not None:
+ params["max_results"] = max_results
if pagination_token is not None:
params["pagination_token"] = pagination_token
- if granularity is not None:
- params["granularity"] = granularity
- if search_countfields is not None:
- params["search_count.fields"] = ",".join(
- str(item) for item in search_countfields
- )
+ 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 = {}
# Prepare request data
json_data = None
@@ -203,34 +309,38 @@ def get_counts_all(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetCountsAllResponse.model_validate(response_data)
+ return GetRepostedByResponse.model_validate(response_data)
- def get_by_id(
+ def get_reposts(
self,
id: Any,
- tweetfields: List = None,
+ max_results: int = None,
+ pagination_token: Any = None,
+ tweet_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
- ) -> GetByIdResponse:
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
+ ) -> GetRepostsResponse:
"""
- Get Post by ID
- Retrieves details of a specific Post by its ID.
+ Get Reposts
+ Retrieves a list of Posts that repost a specific Post by its ID.
Args:
id: A single Post ID.
- tweetfields: A comma separated list of Tweet fields to display.
+ max_results: The maximum number of results.
+ pagination_token: This parameter is used to get the next 'page' of results.
+ tweet_fields: A comma separated list of Tweet fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
Returns:
- GetByIdResponse: Response data
+ GetRepostsResponse: Response data
"""
- url = self.client.base_url + "/2/tweets/{id}"
+ url = self.client.base_url + "/2/tweets/{id}/retweets"
url = url.replace("{id}", str(id))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
@@ -246,18 +356,22 @@ def get_by_id(
if self.client.is_token_expired():
self.client.refresh_token()
params = {}
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
+ 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 = {}
# Prepare request data
json_data = None
@@ -272,20 +386,88 @@ def get_by_id(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetByIdResponse.model_validate(response_data)
+ return GetRepostsResponse.model_validate(response_data)
- def delete(self, id: Any) -> DeleteResponse:
+ def get_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,
+ ) -> GetByIdsResponse:
"""
- Delete Post
- Deletes a specific Post by its ID, if owned by the authenticated user.
+ Get Posts by IDs
+ Retrieves details of multiple Posts by their IDs.
Args:
- id: The ID of the Post to be deleted.
+ ids: A comma separated list of Post IDs. Up to 100 are allowed in a single request.
+ tweet_fields: A comma separated list of Tweet fields to display.
+ expansions: A comma separated list of fields to expand.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
Returns:
- DeleteResponse: Response data
+ GetByIdsResponse: Response data
"""
- url = self.client.base_url + "/2/tweets/{id}"
- url = url.replace("{id}", str(id))
+ 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 = {}
+ # Prepare request data
+ json_data = None
+ # 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 or Edit Post
+ Creates a new Post for the authenticated user, or edits an existing Post when edit_options are provided.
+ 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
@@ -293,66 +475,78 @@ def delete(self, id: Any) -> DeleteResponse:
self.client.refresh_token()
params = {}
headers = {}
+ headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
+ if body is not None:
+ json_data = (
+ body.model_dump(exclude_none=True)
+ if hasattr(body, "model_dump")
+ else body
+ )
# 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=json_data,
)
else:
- response = self.client.session.delete(
+ response = self.client.session.post(
url,
params=params,
headers=headers,
+ json=json_data,
)
# 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)
+ return CreateResponse.model_validate(response_data)
- def get_insights28hr(
+ def get_liking_users(
self,
- tweet_ids: List,
- granularity: str,
- requested_metrics: List,
- engagementfields: List = None,
- ) -> GetInsights28hrResponse:
+ id: Any,
+ max_results: int = None,
+ pagination_token: Any = None,
+ user_fields: List = None,
+ expansions: List = None,
+ tweet_fields: List = None,
+ ) -> GetLikingUsersResponse:
"""
- Get 28-hour Post insights
- Retrieves engagement metrics for specified Posts over the last 28 hours.
+ Get Liking Users
+ Retrieves a list of Users who liked a specific Post by its ID.
Args:
- tweet_ids: List of PostIds for 28hr metrics.
- granularity: granularity of metrics response.
- requested_metrics: request metrics for historical request.
- engagementfields: A comma separated list of Engagement fields to display.
+ id: A single Post ID.
+ max_results: The maximum number of results.
+ pagination_token: This parameter is used to get the next 'page' of results.
+ user_fields: A comma separated list of User fields to display.
+ expansions: A comma separated list of fields to expand.
+ tweet_fields: A comma separated list of Tweet fields to display.
Returns:
- GetInsights28hrResponse: Response data
+ GetLikingUsersResponse: Response data
"""
- url = self.client.base_url + "/2/insights/28hr"
+ url = self.client.base_url + "/2/tweets/{id}/liking_users"
+ url = url.replace("{id}", str(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 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 engagementfields is not None:
- params["engagement.fields"] = ",".join(
- str(item) for item in engagementfields
- )
+ 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)
headers = {}
# Prepare request data
json_data = None
@@ -374,7 +568,7 @@ def get_insights28hr(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetInsights28hrResponse.model_validate(response_data)
+ return GetLikingUsersResponse.model_validate(response_data)
def get_counts_recent(
@@ -387,7 +581,7 @@ def get_counts_recent(
next_token: Any = None,
pagination_token: Any = None,
granularity: str = None,
- search_countfields: List = None,
+ search_count_fields: List = None,
) -> GetCountsRecentResponse:
"""
Get count of recent Posts
@@ -401,7 +595,7 @@ def get_counts_recent(
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.
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.
granularity: The granularity for the search counts results.
- search_countfields: A comma separated list of SearchCount fields to display.
+ search_count_fields: A comma separated list of SearchCount fields to display.
Returns:
GetCountsRecentResponse: Response data
"""
@@ -431,9 +625,9 @@ def get_counts_recent(
params["pagination_token"] = pagination_token
if granularity is not None:
params["granularity"] = granularity
- if search_countfields is not None:
+ if search_count_fields is not None:
params["search_count.fields"] = ",".join(
- str(item) for item in search_countfields
+ str(item) for item in search_count_fields
)
headers = {}
# Prepare request data
@@ -452,47 +646,35 @@ def get_counts_recent(
return GetCountsRecentResponse.model_validate(response_data)
- def search_all(
+ def get_counts_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,
- tweetfields: List = None,
- expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
- ) -> SearchAllResponse:
+ granularity: str = None,
+ search_count_fields: List = None,
+ ) -> GetCountsAllResponse:
"""
- Search all Posts
- Retrieves Posts from the full archive matching a search query.
+ 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.
- 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).
+ 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).
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).
since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID.
until_id: Returns results with a Post ID less than (that is, older than) the specified ID.
- max_results: The maximum number of search results to be returned by a request.
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.
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.
- sort_order: This order in which to return results.
- tweetfields: A comma separated list of Tweet fields to display.
- expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
+ granularity: The granularity for the search counts results.
+ search_count_fields: A comma separated list of SearchCount fields to display.
Returns:
- SearchAllResponse: Response data
+ GetCountsAllResponse: Response data
"""
- url = self.client.base_url + "/2/tweets/search/all"
+ 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}"
@@ -512,26 +694,16 @@ def search_all(
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 tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
- if expansions is not None:
- params["expansions"] = ",".join(str(item) for item in expansions)
- if mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
+ 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 = {}
# Prepare request data
json_data = None
@@ -546,33 +718,50 @@ def search_all(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return SearchAllResponse.model_validate(response_data)
+ return GetCountsAllResponse.model_validate(response_data)
- def get_reposted_by(
+ def search_all(
self,
- id: Any,
+ 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,
- userfields: List = None,
+ sort_order: str = None,
+ tweet_fields: List = None,
expansions: List = None,
- tweetfields: List = None,
- ) -> GetRepostedByResponse:
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
+ ) -> SearchAllResponse:
"""
- Get Reposted by
- Retrieves a list of Users who reposted a specific Post by its ID.
+ Search all Posts
+ Retrieves Posts from the full archive matching a search query.
Args:
- id: A single Post ID.
- max_results: The maximum number of results.
- pagination_token: This parameter is used to get the next 'page' of results.
- userfields: A comma separated list of User fields to display.
+ query: One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length.
+ 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).
+ 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).
+ since_id: Returns results with a Post ID greater than (that is, more recent than) the specified ID.
+ until_id: Returns results with a Post ID less than (that is, older than) the specified ID.
+ max_results: The maximum number of search results to be returned by a request.
+ 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.
+ 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.
+ sort_order: This order in which to return results.
+ tweet_fields: A comma separated list of Tweet fields to display.
expansions: A comma separated list of fields to expand.
- tweetfields: A comma separated list of Tweet fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
Returns:
- GetRepostedByResponse: Response data
+ SearchAllResponse: Response data
"""
- url = self.client.base_url + "/2/tweets/{id}/retweeted_by"
- url = url.replace("{id}", str(id))
+ 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}"
@@ -581,22 +770,37 @@ def get_reposted_by(
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 userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
+ 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 tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 = {}
# Prepare request data
json_data = None
@@ -611,7 +815,7 @@ def get_reposted_by(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetRepostedByResponse.model_validate(response_data)
+ return SearchAllResponse.model_validate(response_data)
def search_recent(
@@ -625,12 +829,12 @@ def search_recent(
next_token: Any = None,
pagination_token: Any = None,
sort_order: str = None,
- tweetfields: List = None,
+ tweet_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
) -> SearchRecentResponse:
"""
Search recent Posts
@@ -645,12 +849,12 @@ def search_recent(
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.
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.
sort_order: This order in which to return results.
- tweetfields: A comma separated list of Tweet fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
Returns:
SearchRecentResponse: Response data
"""
@@ -687,18 +891,18 @@ def search_recent(
params["pagination_token"] = pagination_token
if sort_order is not None:
params["sort_order"] = sort_order
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
+ 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 = {}
# Prepare request data
json_data = None
@@ -723,7 +927,7 @@ def get_insights_historical(
start_time: str,
granularity: str,
requested_metrics: List,
- engagementfields: List = None,
+ engagement_fields: List = None,
) -> GetInsightsHistoricalResponse:
"""
Get historical Post insights
@@ -734,7 +938,7 @@ def get_insights_historical(
start_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range.
granularity: granularity of metrics response.
requested_metrics: request metrics for historical request.
- engagementfields: A comma separated list of Engagement fields to display.
+ engagement_fields: A comma separated list of Engagement fields to display.
Returns:
GetInsightsHistoricalResponse: Response data
"""
@@ -757,9 +961,9 @@ def get_insights_historical(
params["requested_metrics"] = ",".join(
str(item) for item in requested_metrics
)
- if engagementfields is not None:
+ if engagement_fields is not None:
params["engagement.fields"] = ",".join(
- str(item) for item in engagementfields
+ str(item) for item in engagement_fields
)
headers = {}
# Prepare request data
@@ -785,31 +989,32 @@ def get_insights_historical(
return GetInsightsHistoricalResponse.model_validate(response_data)
- def get_by_ids(
+ def get_by_id(
self,
- ids: List,
- tweetfields: List = None,
+ id: Any,
+ tweet_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
- ) -> GetByIdsResponse:
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
+ ) -> GetByIdResponse:
"""
- Get Posts by IDs
- Retrieves details of multiple Posts by their IDs.
+ Get Post by ID
+ Retrieves details of a specific Post by its ID.
Args:
- ids: A comma separated list of Post IDs. Up to 100 are allowed in a single request.
- tweetfields: A comma separated list of Tweet fields to display.
+ id: A single Post ID.
+ tweet_fields: A comma separated list of Tweet fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
Returns:
- GetByIdsResponse: Response data
+ GetByIdResponse: Response data
"""
- url = self.client.base_url + "/2/tweets"
+ url = self.client.base_url + "/2/tweets/{id}"
+ url = url.replace("{id}", str(id))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
f"Bearer {self.client.bearer_token}"
@@ -824,20 +1029,18 @@ def get_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 tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
+ 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 = {}
# Prepare request data
json_data = None
@@ -852,80 +1055,19 @@ def get_by_ids(
# 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 or Edit Post
- Creates a new Post for the authenticated user, or edits an existing Post when edit_options are provided.
- 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"
- # Prepare request data
- json_data = None
- if body is not None:
- json_data = (
- body.model_dump(exclude_none=True)
- if hasattr(body, "model_dump")
- else body
- )
- # Make the request
- if self.client.oauth2_session:
- response = self.client.oauth2_session.post(
- url,
- params=params,
- headers=headers,
- json=json_data,
- )
- else:
- response = self.client.session.post(
- url,
- params=params,
- headers=headers,
- json=json_data,
- )
- # 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)
+ return GetByIdResponse.model_validate(response_data)
- def get_liking_users(
- self,
- id: Any,
- max_results: int = None,
- pagination_token: Any = None,
- userfields: List = None,
- expansions: List = None,
- tweetfields: List = None,
- ) -> GetLikingUsersResponse:
+ def delete(self, id: Any) -> DeleteResponse:
"""
- Get Liking Users
- Retrieves a list of Users who liked a specific Post by its ID.
+ Delete Post
+ Deletes a specific Post by its ID, if owned by the authenticated user.
Args:
- id: A single Post ID.
- max_results: The maximum number of results.
- pagination_token: This parameter is used to get the next 'page' of results.
- userfields: A comma separated list of User fields to display.
- expansions: A comma separated list of fields to expand.
- tweetfields: A comma separated list of Tweet fields to display.
+ id: The ID of the Post to be deleted.
Returns:
- GetLikingUsersResponse: Response data
+ DeleteResponse: Response data
"""
- url = self.client.base_url + "/2/tweets/{id}/liking_users"
+ url = self.client.base_url + "/2/tweets/{id}"
url = url.replace("{id}", str(id))
# Ensure we have a valid access token
if self.client.oauth2_auth and self.client.token:
@@ -933,28 +1075,18 @@ def get_liking_users(
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 userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if expansions is not None:
- params["expansions"] = ",".join(str(item) for item in expansions)
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
headers = {}
# Prepare request data
json_data = None
# 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,
@@ -964,195 +1096,65 @@ def get_liking_users(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetLikingUsersResponse.model_validate(response_data)
+ return DeleteResponse.model_validate(response_data)
- def get_analytics(
+ def get_insights28hr(
self,
- ids: List,
- end_time: str,
- start_time: str,
+ tweet_ids: List,
granularity: str,
- analyticsfields: List = None,
- ) -> GetAnalyticsResponse:
+ requested_metrics: List,
+ engagement_fields: List = None,
+ ) -> GetInsights28hrResponse:
"""
- Get Post analytics
- Retrieves analytics data for specified Posts within a defined time range.
+ Get 28-hour Post insights
+ Retrieves engagement metrics for specified Posts over the last 28 hours.
Args:
- ids: A comma separated list of Post IDs. Up to 100 are allowed in a single request.
- end_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range.
- start_time: YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range.
- granularity: The granularity for the search counts results.
- analyticsfields: A comma separated list of Analytics fields to display.
+ tweet_ids: List of PostIds for 28hr metrics.
+ granularity: granularity of metrics response.
+ requested_metrics: request metrics for historical request.
+ engagement_fields: A comma separated list of Engagement fields to display.
Returns:
- GetAnalyticsResponse: Response data
+ GetInsights28hrResponse: Response data
"""
- url = self.client.base_url + "/2/tweets/analytics"
+ 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 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 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 analyticsfields is not None:
- params["analytics.fields"] = ",".join(str(item) for item in analyticsfields)
- headers = {}
- # Prepare request data
- json_data = None
- # Make the request
- if self.client.oauth2_session:
- response = self.client.oauth2_session.get(
- url,
- params=params,
- headers=headers,
+ if requested_metrics is not None:
+ params["requested_metrics"] = ",".join(
+ str(item) for item in requested_metrics
)
- else:
- response = self.client.session.get(
- url,
- params=params,
- headers=headers,
+ if engagement_fields is not None:
+ params["engagement.fields"] = ",".join(
+ str(item) for item in engagement_fields
)
- # 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 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"
- url = url.replace("{tweet_id}", str(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 = {}
headers = {}
- headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
- if body is not None:
- json_data = (
- body.model_dump(exclude_none=True)
- if hasattr(body, "model_dump")
- else body
- )
# Make the request
if self.client.oauth2_session:
- response = self.client.oauth2_session.put(
+ response = self.client.oauth2_session.get(
url,
params=params,
headers=headers,
- json=json_data,
)
else:
- response = self.client.session.put(
+ response = self.client.session.get(
url,
params=params,
headers=headers,
- json=json_data,
- )
- # 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 get_reposts(
- self,
- id: Any,
- max_results: int = None,
- pagination_token: Any = None,
- tweetfields: List = None,
- expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
- ) -> GetRepostsResponse:
- """
- Get Reposts
- Retrieves a list of Posts that repost a specific Post by its ID.
- Args:
- id: A single Post ID.
- max_results: The maximum number of results.
- pagination_token: This parameter is used to get the next 'page' of results.
- tweetfields: A comma separated list of Tweet fields to display.
- expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
- Returns:
- GetRepostsResponse: Response data
- """
- url = self.client.base_url + "/2/tweets/{id}/retweets"
- url = url.replace("{id}", str(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 max_results is not None:
- params["max_results"] = max_results
- if pagination_token is not None:
- params["pagination_token"] = pagination_token
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
- if expansions is not None:
- params["expansions"] = ",".join(str(item) for item in expansions)
- if mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
- headers = {}
- # Prepare request data
- json_data = None
- # 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)
+ return GetInsights28hrResponse.model_validate(response_data)
diff --git a/xdk/python/xdk/posts/models.py b/xdk/python/xdk/posts/models.py
index 9ae38dfe..fb341edb 100644
--- a/xdk/python/xdk/posts/models.py
+++ b/xdk/python/xdk/posts/models.py
@@ -25,148 +25,148 @@ class GetQuotedResponse(BaseModel):
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_counts_all
+# Models for get_analytics
-class GetCountsAllResponse(BaseModel):
- """Response model for get_counts_all"""
+class GetAnalyticsResponse(BaseModel):
+ """Response model for get_analytics"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_by_id
-
+# Models for hide_reply
-class GetByIdResponse(BaseModel):
- """Response model for get_by_id"""
-
- model_config = ConfigDict(populate_by_name=True, extra="allow")
+class HideReplyRequest(BaseModel):
+ """Request model for hide_reply"""
-# Models for delete
+ model_config = ConfigDict(populate_by_name=True)
-class DeleteResponse(BaseModel):
- """Response model for delete"""
+class HideReplyResponse(BaseModel):
+ """Response model for hide_reply"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_insights28hr
+# Models for get_reposted_by
-class GetInsights28hrResponse(BaseModel):
- """Response model for get_insights28hr"""
+class GetRepostedByResponse(BaseModel):
+ """Response model for get_reposted_by"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_counts_recent
+# Models for get_reposts
-class GetCountsRecentResponse(BaseModel):
- """Response model for get_counts_recent"""
+class GetRepostsResponse(BaseModel):
+ """Response model for get_reposts"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for search_all
+# Models for get_by_ids
-class SearchAllResponse(BaseModel):
- """Response model for search_all"""
+class GetByIdsResponse(BaseModel):
+ """Response model for get_by_ids"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_reposted_by
-
-
-class GetRepostedByResponse(BaseModel):
- """Response model for get_reposted_by"""
+# Models for create
- model_config = ConfigDict(populate_by_name=True, extra="allow")
+class CreateRequest(BaseModel):
+ """Request model for create"""
-# Models for search_recent
+ model_config = ConfigDict(populate_by_name=True)
-class SearchRecentResponse(BaseModel):
- """Response model for search_recent"""
+class CreateResponse(BaseModel):
+ """Response model for create"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_insights_historical
+# Models for get_liking_users
-class GetInsightsHistoricalResponse(BaseModel):
- """Response model for get_insights_historical"""
+class GetLikingUsersResponse(BaseModel):
+ """Response model for get_liking_users"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_by_ids
+# Models for get_counts_recent
-class GetByIdsResponse(BaseModel):
- """Response model for get_by_ids"""
+class GetCountsRecentResponse(BaseModel):
+ """Response model for get_counts_recent"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for create
+# Models for get_counts_all
-class CreateRequest(BaseModel):
- """Request model for create"""
+class GetCountsAllResponse(BaseModel):
+ """Response model for get_counts_all"""
- model_config = ConfigDict(populate_by_name=True)
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
-class CreateResponse(BaseModel):
- """Response model for create"""
+# Models for search_all
+
+
+class SearchAllResponse(BaseModel):
+ """Response model for search_all"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_liking_users
+# Models for search_recent
-class GetLikingUsersResponse(BaseModel):
- """Response model for get_liking_users"""
+class SearchRecentResponse(BaseModel):
+ """Response model for search_recent"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_analytics
+# Models for get_insights_historical
-class GetAnalyticsResponse(BaseModel):
- """Response model for get_analytics"""
+class GetInsightsHistoricalResponse(BaseModel):
+ """Response model for get_insights_historical"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for hide_reply
+# Models for get_by_id
-class HideReplyRequest(BaseModel):
- """Request model for hide_reply"""
+class GetByIdResponse(BaseModel):
+ """Response model for get_by_id"""
- model_config = ConfigDict(populate_by_name=True)
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
-class HideReplyResponse(BaseModel):
- """Response model for hide_reply"""
+# Models for delete
+
+
+class DeleteResponse(BaseModel):
+ """Response model for delete"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_reposts
+# Models for get_insights28hr
-class GetRepostsResponse(BaseModel):
- """Response model for get_reposts"""
+class GetInsights28hrResponse(BaseModel):
+ """Response model for get_insights28hr"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
diff --git a/xdk/python/xdk/spaces/client.py b/xdk/python/xdk/spaces/client.py
index 1e4ec10d..b1f8926d 100644
--- a/xdk/python/xdk/spaces/client.py
+++ b/xdk/python/xdk/spaces/client.py
@@ -21,12 +21,12 @@
if TYPE_CHECKING:
from ..client import Client
from .models import (
- GetByCreatorIdsResponse,
- GetByIdResponse,
- GetByIdsResponse,
GetPostsResponse,
- GetBuyersResponse,
SearchResponse,
+ GetBuyersResponse,
+ GetByIdResponse,
+ GetByIdsResponse,
+ GetByCreatorIdsResponse,
)
@@ -38,27 +38,34 @@ def __init__(self, client: Client):
self.client = client
- def get_by_creator_ids(
+ def get_posts(
self,
- user_ids: List,
- spacefields: List = None,
+ id: str,
+ max_results: int = None,
+ tweet_fields: List = None,
expansions: List = None,
- userfields: List = None,
- topicfields: List = None,
- ) -> GetByCreatorIdsResponse:
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
+ ) -> GetPostsResponse:
"""
- Get Spaces by creator IDs
- Retrieves details of Spaces created by specified User IDs.
+ Get Space Posts
+ Retrieves a list of Posts shared in a specific Space by its ID.
Args:
- user_ids: The IDs of Users to search through.
- spacefields: A comma separated list of Space fields to display.
+ id: The ID of the Space to be retrieved.
+ max_results: The number of Posts to fetch from the provided space. If not provided, the value will default to the maximum of 100.
+ tweet_fields: A comma separated list of Tweet fields to display.
expansions: A comma separated list of fields to expand.
- userfields: A comma separated list of User fields to display.
- topicfields: A comma separated list of Topic fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
Returns:
- GetByCreatorIdsResponse: Response data
+ GetPostsResponse: Response data
"""
- url = self.client.base_url + "/2/spaces/by/creator_ids"
+ url = self.client.base_url + "/2/spaces/{id}/tweets"
+ url = url.replace("{id}", str(id))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
f"Bearer {self.client.bearer_token}"
@@ -73,16 +80,20 @@ def get_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 spacefields is not None:
- params["space.fields"] = ",".join(str(item) for item in spacefields)
+ 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 userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if topicfields is not None:
- params["topic.fields"] = ",".join(str(item) for item in topicfields)
+ 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 = {}
# Prepare request data
json_data = None
@@ -97,31 +108,34 @@ def get_by_creator_ids(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetByCreatorIdsResponse.model_validate(response_data)
+ return GetPostsResponse.model_validate(response_data)
- def get_by_id(
+ def search(
self,
- id: str,
- spacefields: List = None,
+ query: str,
+ state: str = None,
+ max_results: int = None,
+ space_fields: List = None,
expansions: List = None,
- userfields: List = None,
- topicfields: List = None,
- ) -> GetByIdResponse:
+ user_fields: List = None,
+ topic_fields: List = None,
+ ) -> SearchResponse:
"""
- Get space by ID
- Retrieves details of a specific space by its ID.
+ Search Spaces
+ Retrieves a list of Spaces matching the specified search query.
Args:
- id: The ID of the Space to be retrieved.
- spacefields: A comma separated list of Space fields to display.
+ query: The search query.
+ state: The state of Spaces to search for.
+ max_results: The number of results to return.
+ space_fields: A comma separated list of Space fields to display.
expansions: A comma separated list of fields to expand.
- userfields: A comma separated list of User fields to display.
- topicfields: A comma separated list of Topic fields to display.
+ user_fields: A comma separated list of User fields to display.
+ topic_fields: A comma separated list of Topic fields to display.
Returns:
- GetByIdResponse: Response data
+ SearchResponse: Response data
"""
- url = self.client.base_url + "/2/spaces/{id}"
- url = url.replace("{id}", str(id))
+ url = self.client.base_url + "/2/spaces/search"
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
f"Bearer {self.client.bearer_token}"
@@ -136,14 +150,20 @@ def get_by_id(
if self.client.is_token_expired():
self.client.refresh_token()
params = {}
- if spacefields is not None:
- params["space.fields"] = ",".join(str(item) for item in spacefields)
+ 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 userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if topicfields is not None:
- params["topic.fields"] = ",".join(str(item) for item in topicfields)
+ 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 = {}
# Prepare request data
json_data = None
@@ -158,98 +178,94 @@ def get_by_id(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetByIdResponse.model_validate(response_data)
+ return SearchResponse.model_validate(response_data)
- def get_by_ids(
+ def get_buyers(
self,
- ids: List,
- spacefields: List = None,
+ id: str,
+ pagination_token: Any = None,
+ max_results: int = None,
+ user_fields: List = None,
expansions: List = None,
- userfields: List = None,
- topicfields: List = None,
- ) -> GetByIdsResponse:
+ tweet_fields: List = None,
+ ) -> GetBuyersResponse:
"""
- Get Spaces by IDs
- Retrieves details of multiple Spaces by their IDs.
+ Get Space ticket buyers
+ Retrieves a list of Users who purchased tickets to a specific Space by its ID.
Args:
- ids: The list of Space IDs to return.
- spacefields: A comma separated list of Space fields to display.
+ id: The ID of the Space to be retrieved.
+ pagination_token: This parameter is used to get a specified 'page' of results.
+ max_results: The maximum number of results.
+ user_fields: A comma separated list of User fields to display.
expansions: A comma separated list of fields to expand.
- userfields: A comma separated list of User fields to display.
- topicfields: A comma separated list of Topic fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
Returns:
- GetByIdsResponse: Response data
+ GetBuyersResponse: 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}"
- )
+ url = self.client.base_url + "/2/spaces/{id}/buyers"
+ url = url.replace("{id}", str(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 ids is not None:
- params["ids"] = ",".join(str(item) for item in ids)
- if spacefields is not None:
- params["space.fields"] = ",".join(str(item) for item in spacefields)
+ 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 userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if topicfields is not None:
- params["topic.fields"] = ",".join(str(item) for item in topicfields)
+ if tweet_fields is not None:
+ params["tweet.fields"] = ",".join(str(item) for item in tweet_fields)
headers = {}
# Prepare request data
json_data = None
# 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 GetByIdsResponse.model_validate(response_data)
+ return GetBuyersResponse.model_validate(response_data)
- def get_posts(
+ def get_by_id(
self,
id: str,
- max_results: int = None,
- tweetfields: List = None,
+ space_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
- ) -> GetPostsResponse:
+ user_fields: List = None,
+ topic_fields: List = None,
+ ) -> GetByIdResponse:
"""
- Get Space Posts
- Retrieves a list of Posts shared in a specific Space by its ID.
+ Get space by ID
+ Retrieves details of a specific space by its ID.
Args:
id: The ID of the Space to be retrieved.
- max_results: The number of Posts to fetch from the provided space. If not provided, the value will default to the maximum of 100.
- tweetfields: A comma separated list of Tweet fields to display.
+ space_fields: A comma separated list of Space fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
+ user_fields: A comma separated list of User fields to display.
+ topic_fields: A comma separated list of Topic fields to display.
Returns:
- GetPostsResponse: Response data
+ GetByIdResponse: Response data
"""
- url = self.client.base_url + "/2/spaces/{id}/tweets"
+ url = self.client.base_url + "/2/spaces/{id}"
url = url.replace("{id}", str(id))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
@@ -265,20 +281,14 @@ def get_posts(
if self.client.is_token_expired():
self.client.refresh_token()
params = {}
- if max_results is not None:
- params["max_results"] = max_results
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
+ 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 = {}
# Prepare request data
json_data = None
@@ -293,98 +303,92 @@ def get_posts(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetPostsResponse.model_validate(response_data)
+ return GetByIdResponse.model_validate(response_data)
- def get_buyers(
+ def get_by_ids(
self,
- id: str,
- pagination_token: Any = None,
- max_results: int = None,
- userfields: List = None,
+ ids: List,
+ space_fields: List = None,
expansions: List = None,
- tweetfields: List = None,
- ) -> GetBuyersResponse:
+ user_fields: List = None,
+ topic_fields: List = None,
+ ) -> GetByIdsResponse:
"""
- Get Space ticket buyers
- Retrieves a list of Users who purchased tickets to a specific Space by its ID.
+ Get Spaces by IDs
+ Retrieves details of multiple Spaces by their IDs.
Args:
- id: The ID of the Space to be retrieved.
- pagination_token: This parameter is used to get a specified 'page' of results.
- max_results: The maximum number of results.
- userfields: A comma separated list of User fields to display.
+ ids: The list of Space IDs to return.
+ space_fields: A comma separated list of Space fields to display.
expansions: A comma separated list of fields to expand.
- tweetfields: A comma separated list of Tweet fields to display.
+ user_fields: A comma separated list of User fields to display.
+ topic_fields: A comma separated list of Topic fields to display.
Returns:
- GetBuyersResponse: Response data
+ GetByIdsResponse: Response data
"""
- url = self.client.base_url + "/2/spaces/{id}/buyers"
- url = url.replace("{id}", str(id))
+ 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 pagination_token is not None:
- params["pagination_token"] = pagination_token
- if max_results is not None:
- params["max_results"] = max_results
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
+ 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 tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 = {}
# Prepare request data
json_data = None
# 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 GetBuyersResponse.model_validate(response_data)
+ return GetByIdsResponse.model_validate(response_data)
- def search(
+ def get_by_creator_ids(
self,
- query: str,
- state: str = None,
- max_results: int = None,
- spacefields: List = None,
+ user_ids: List,
+ space_fields: List = None,
expansions: List = None,
- userfields: List = None,
- topicfields: List = None,
- ) -> SearchResponse:
+ user_fields: List = None,
+ topic_fields: List = None,
+ ) -> GetByCreatorIdsResponse:
"""
- Search Spaces
- Retrieves a list of Spaces matching the specified search query.
+ Get Spaces by creator IDs
+ Retrieves details of Spaces created by specified User IDs.
Args:
- query: The search query.
- state: The state of Spaces to search for.
- max_results: The number of results to return.
- spacefields: A comma separated list of Space fields to display.
+ user_ids: The IDs of Users to search through.
+ space_fields: A comma separated list of Space fields to display.
expansions: A comma separated list of fields to expand.
- userfields: A comma separated list of User fields to display.
- topicfields: A comma separated list of Topic fields to display.
+ user_fields: A comma separated list of User fields to display.
+ topic_fields: A comma separated list of Topic fields to display.
Returns:
- SearchResponse: 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}"
@@ -399,20 +403,16 @@ def search(
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 spacefields is not None:
- params["space.fields"] = ",".join(str(item) for item in spacefields)
+ 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 userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if topicfields is not None:
- params["topic.fields"] = ",".join(str(item) for item in topicfields)
+ 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 = {}
# Prepare request data
json_data = None
@@ -427,4 +427,4 @@ def search(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return SearchResponse.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 ebbc7904..1a9ca7a9 100644
--- a/xdk/python/xdk/spaces/models.py
+++ b/xdk/python/xdk/spaces/models.py
@@ -16,55 +16,55 @@
from datetime import datetime
-# Models for get_by_creator_ids
+# Models for get_posts
-class GetByCreatorIdsResponse(BaseModel):
- """Response model for get_by_creator_ids"""
+class GetPostsResponse(BaseModel):
+ """Response model for get_posts"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_by_id
+# Models for search
-class GetByIdResponse(BaseModel):
- """Response model for get_by_id"""
+class SearchResponse(BaseModel):
+ """Response model for search"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_by_ids
+# Models for get_buyers
-class GetByIdsResponse(BaseModel):
- """Response model for get_by_ids"""
+class GetBuyersResponse(BaseModel):
+ """Response model for get_buyers"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_posts
+# Models for get_by_id
-class GetPostsResponse(BaseModel):
- """Response model for get_posts"""
+class GetByIdResponse(BaseModel):
+ """Response model for get_by_id"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_buyers
+# Models for get_by_ids
-class GetBuyersResponse(BaseModel):
- """Response model for get_buyers"""
+class GetByIdsResponse(BaseModel):
+ """Response model for get_by_ids"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for search
+# Models for get_by_creator_ids
-class SearchResponse(BaseModel):
- """Response model for search"""
+class GetByCreatorIdsResponse(BaseModel):
+ """Response model for get_by_creator_ids"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
diff --git a/xdk/python/xdk/stream/client.py b/xdk/python/xdk/stream/client.py
index f3f2f9e2..ac38eea8 100644
--- a/xdk/python/xdk/stream/client.py
+++ b/xdk/python/xdk/stream/client.py
@@ -31,24 +31,24 @@
if TYPE_CHECKING:
from ..client import Client
from .models import (
- PostsSampleResponse,
- GetRuleCountsResponse,
- PostsFirehoseResponse,
+ LikesFirehoseResponse,
PostsFirehosePtResponse,
- UsersComplianceResponse,
- PostsSample10Response,
- LikesComplianceResponse,
+ PostsFirehoseJaResponse,
LabelsComplianceResponse,
- PostsFirehoseEnResponse,
- PostsResponse,
PostsFirehoseKoResponse,
- LikesSample10Response,
- PostsComplianceResponse,
+ PostsResponse,
+ LikesComplianceResponse,
GetRulesResponse,
UpdateRulesRequest,
UpdateRulesResponse,
- PostsFirehoseJaResponse,
- LikesFirehoseResponse,
+ GetRuleCountsResponse,
+ LikesSample10Response,
+ PostsFirehoseResponse,
+ UsersComplianceResponse,
+ PostsComplianceResponse,
+ PostsSample10Response,
+ PostsFirehoseEnResponse,
+ PostsSampleResponse,
)
@@ -60,40 +60,42 @@ def __init__(self, client: Client):
self.client = client
- def posts_sample(
+ def likes_firehose(
self,
+ partition: int,
backfill_minutes: int = None,
- tweetfields: List = None,
+ start_time: str = None,
+ end_time: str = None,
+ like_with_tweet_author_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
+ user_fields: List = None,
+ tweet_fields: List = None,
timeout: Optional[float] = None,
chunk_size: int = 1024,
- ) -> Generator[PostsSampleResponse, None, None]:
+ ) -> Generator[LikesFirehoseResponse, None, None]:
"""
- Stream sampled Posts (Streaming)
- Streams a 1% sample of public Posts in real-time.
+ Stream all Likes (Streaming)
+ Streams all public Likes in real-time.
This is a streaming endpoint that yields data in real-time as it becomes available.
Each yielded item represents a single data point from the stream.
Args:
backfill_minutes: The number of minutes of backfill requested.
- tweetfields: A comma separated list of Tweet fields to display.
+ partition: The partition number.
+ start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Likes will be provided.
+ end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided.
+ like_with_tweet_author_fields: A comma separated list of LikeWithTweetAuthor fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
+ user_fields: A comma separated list of User fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
timeout: Request timeout in seconds (default: None for no timeout)
chunk_size: Size of chunks to read from the stream (default: 1024 bytes)
Yields:
- PostsSampleResponse: Individual streaming data items
+ LikesFirehoseResponse: Individual streaming data items
Raises:
requests.exceptions.RequestException: If the streaming connection fails
json.JSONDecodeError: If the streamed data is not valid JSON
"""
- url = self.client.base_url + "/2/tweets/sample/stream"
+ 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}"
@@ -105,18 +107,22 @@ def posts_sample(
params = {}
if backfill_minutes is not None:
params["backfill_minutes"] = backfill_minutes
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
+ 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 = {
"Accept": "application/json",
}
@@ -153,7 +159,7 @@ def posts_sample(
# Parse JSON line
data = json.loads(line)
# Convert to response model if available
- yield PostsSampleResponse.model_validate(data)
+ yield LikesFirehoseResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON lines
continue
@@ -164,7 +170,7 @@ def posts_sample(
if buffer.strip():
try:
data = json.loads(buffer.strip())
- yield PostsSampleResponse.model_validate(data)
+ yield LikesFirehoseResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON in final buffer
pass
@@ -174,64 +180,24 @@ def posts_sample(
raise
- def get_rule_counts(self, rules_countfields: List = None) -> GetRuleCountsResponse:
- """
- Get stream rule counts
- Retrieves the count of rules in the active rule set for the filtered stream.
- Args:
- rules_countfields: 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_countfields is not None:
- params["rules_count.fields"] = ",".join(
- str(item) for item in rules_countfields
- )
- headers = {}
- # Prepare request data
- json_data = None
- # 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(
+ def posts_firehose_pt(
self,
partition: int,
backfill_minutes: int = None,
start_time: str = None,
end_time: str = None,
- tweetfields: List = None,
+ tweet_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
timeout: Optional[float] = None,
chunk_size: int = 1024,
- ) -> Generator[PostsFirehoseResponse, None, None]:
+ ) -> Generator[PostsFirehosePtResponse, None, None]:
"""
- Stream all Posts (Streaming)
- Streams all public Posts in real-time.
+ Stream Portuguese Posts (Streaming)
+ Streams all public Portuguese-language Posts in real-time.
This is a streaming endpoint that yields data in real-time as it becomes available.
Each yielded item represents a single data point from the stream.
Args:
@@ -239,21 +205,21 @@ def posts_firehose(
partition: The partition number.
start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided.
end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided.
- tweetfields: A comma separated list of Tweet fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
timeout: Request timeout in seconds (default: None for no timeout)
chunk_size: Size of chunks to read from the stream (default: 1024 bytes)
Yields:
- PostsFirehoseResponse: Individual streaming data items
+ PostsFirehosePtResponse: Individual streaming data items
Raises:
requests.exceptions.RequestException: If the streaming connection fails
json.JSONDecodeError: If the streamed data is not valid JSON
"""
- url = self.client.base_url + "/2/tweets/firehose/stream"
+ 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}"
@@ -271,18 +237,18 @@ def posts_firehose(
params["start_time"] = start_time
if end_time is not None:
params["end_time"] = end_time
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
+ 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 = {
"Accept": "application/json",
}
@@ -319,7 +285,7 @@ def posts_firehose(
# Parse JSON line
data = json.loads(line)
# Convert to response model if available
- yield PostsFirehoseResponse.model_validate(data)
+ yield PostsFirehosePtResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON lines
continue
@@ -330,7 +296,7 @@ def posts_firehose(
if buffer.strip():
try:
data = json.loads(buffer.strip())
- yield PostsFirehoseResponse.model_validate(data)
+ yield PostsFirehosePtResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON in final buffer
pass
@@ -340,24 +306,24 @@ def posts_firehose(
raise
- def posts_firehose_pt(
+ def posts_firehose_ja(
self,
partition: int,
backfill_minutes: int = None,
start_time: str = None,
end_time: str = None,
- tweetfields: List = None,
+ tweet_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
timeout: Optional[float] = None,
chunk_size: int = 1024,
- ) -> Generator[PostsFirehosePtResponse, None, None]:
+ ) -> Generator[PostsFirehoseJaResponse, None, None]:
"""
- Stream Portuguese Posts (Streaming)
- Streams all public Portuguese-language Posts in real-time.
+ Stream Japanese Posts (Streaming)
+ Streams all public Japanese-language Posts in real-time.
This is a streaming endpoint that yields data in real-time as it becomes available.
Each yielded item represents a single data point from the stream.
Args:
@@ -365,21 +331,21 @@ def posts_firehose_pt(
partition: The partition number.
start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided.
end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided.
- tweetfields: A comma separated list of Tweet fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
timeout: Request timeout in seconds (default: None for no timeout)
chunk_size: Size of chunks to read from the stream (default: 1024 bytes)
Yields:
- PostsFirehosePtResponse: Individual streaming data items
+ PostsFirehoseJaResponse: Individual streaming data items
Raises:
requests.exceptions.RequestException: If the streaming connection fails
json.JSONDecodeError: If the streamed data is not valid JSON
"""
- url = self.client.base_url + "/2/tweets/firehose/stream/lang/pt"
+ 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}"
@@ -397,18 +363,18 @@ def posts_firehose_pt(
params["start_time"] = start_time
if end_time is not None:
params["end_time"] = end_time
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
+ 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 = {
"Accept": "application/json",
}
@@ -445,7 +411,7 @@ def posts_firehose_pt(
# Parse JSON line
data = json.loads(line)
# Convert to response model if available
- yield PostsFirehosePtResponse.model_validate(data)
+ yield PostsFirehoseJaResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON lines
continue
@@ -456,7 +422,7 @@ def posts_firehose_pt(
if buffer.strip():
try:
data = json.loads(buffer.strip())
- yield PostsFirehosePtResponse.model_validate(data)
+ yield PostsFirehoseJaResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON in final buffer
pass
@@ -466,34 +432,32 @@ def posts_firehose_pt(
raise
- def users_compliance(
+ def labels_compliance(
self,
- partition: int,
backfill_minutes: int = None,
start_time: str = None,
end_time: str = None,
timeout: Optional[float] = None,
chunk_size: int = 1024,
- ) -> Generator[UsersComplianceResponse, None, None]:
+ ) -> Generator[LabelsComplianceResponse, None, None]:
"""
- Stream Users compliance data (Streaming)
- Streams all compliance data related to Users.
+ Stream Post labels (Streaming)
+ Streams all labeling events applied to Posts.
This is a streaming endpoint that yields data in real-time as it becomes available.
Each yielded item represents a single data point from the stream.
Args:
backfill_minutes: The number of minutes of backfill requested.
- partition: The partition number.
- start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest 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 User Compliance events will be provided.
+ start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Post labels will be provided.
+ end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp from which the Post labels will be provided.
timeout: Request timeout in seconds (default: None for no timeout)
chunk_size: Size of chunks to read from the stream (default: 1024 bytes)
Yields:
- UsersComplianceResponse: Individual streaming data items
+ LabelsComplianceResponse: Individual streaming data items
Raises:
requests.exceptions.RequestException: If the streaming connection fails
json.JSONDecodeError: If the streamed data is not valid JSON
"""
- url = self.client.base_url + "/2/users/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}"
@@ -505,8 +469,6 @@ def 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:
@@ -547,7 +509,7 @@ def users_compliance(
# Parse JSON line
data = json.loads(line)
# Convert to response model if available
- yield UsersComplianceResponse.model_validate(data)
+ yield LabelsComplianceResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON lines
continue
@@ -558,7 +520,7 @@ def users_compliance(
if buffer.strip():
try:
data = json.loads(buffer.strip())
- yield UsersComplianceResponse.model_validate(data)
+ yield LabelsComplianceResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON in final buffer
pass
@@ -568,24 +530,24 @@ def users_compliance(
raise
- def posts_sample10(
+ def posts_firehose_ko(
self,
partition: int,
backfill_minutes: int = None,
start_time: str = None,
end_time: str = None,
- tweetfields: List = None,
+ tweet_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
timeout: Optional[float] = None,
chunk_size: int = 1024,
- ) -> Generator[PostsSample10Response, None, None]:
+ ) -> Generator[PostsFirehoseKoResponse, None, None]:
"""
- Stream 10% sampled Posts (Streaming)
- Streams a 10% sample of public Posts in real-time.
+ Stream Korean Posts (Streaming)
+ Streams all public Korean-language Posts in real-time.
This is a streaming endpoint that yields data in real-time as it becomes available.
Each yielded item represents a single data point from the stream.
Args:
@@ -593,21 +555,21 @@ def posts_sample10(
partition: The partition number.
start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided.
end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided.
- tweetfields: A comma separated list of Tweet fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
timeout: Request timeout in seconds (default: None for no timeout)
chunk_size: Size of chunks to read from the stream (default: 1024 bytes)
Yields:
- PostsSample10Response: Individual streaming data items
+ PostsFirehoseKoResponse: Individual streaming data items
Raises:
requests.exceptions.RequestException: If the streaming connection fails
json.JSONDecodeError: If the streamed data is not valid JSON
"""
- url = self.client.base_url + "/2/tweets/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}"
@@ -625,18 +587,18 @@ def posts_sample10(
params["start_time"] = start_time
if end_time is not None:
params["end_time"] = end_time
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
+ 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 = {
"Accept": "application/json",
}
@@ -673,7 +635,7 @@ def posts_sample10(
# Parse JSON line
data = json.loads(line)
# Convert to response model if available
- yield PostsSample10Response.model_validate(data)
+ yield PostsFirehoseKoResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON lines
continue
@@ -684,7 +646,7 @@ def posts_sample10(
if buffer.strip():
try:
data = json.loads(buffer.strip())
- yield PostsSample10Response.model_validate(data)
+ yield PostsFirehoseKoResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON in final buffer
pass
@@ -694,32 +656,44 @@ def posts_sample10(
raise
- def likes_compliance(
+ def 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,
timeout: Optional[float] = None,
chunk_size: int = 1024,
- ) -> Generator[LikesComplianceResponse, None, None]:
+ ) -> Generator[PostsResponse, None, None]:
"""
- Stream Likes compliance data (Streaming)
- Streams all compliance data related to Likes for Users.
+ Stream filtered Posts (Streaming)
+ Streams Posts in real-time matching the active rule set.
This is a streaming endpoint that yields data in real-time as it becomes available.
Each yielded item represents a single data point from the stream.
Args:
backfill_minutes: The number of minutes of backfill requested.
- start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Likes 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.
+ start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Posts will be provided.
+ end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided.
+ tweet_fields: A comma separated list of Tweet fields to display.
+ expansions: A comma separated list of fields to expand.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
timeout: Request timeout in seconds (default: None for no timeout)
chunk_size: Size of chunks to read from the stream (default: 1024 bytes)
Yields:
- LikesComplianceResponse: Individual streaming data items
+ PostsResponse: Individual streaming data items
Raises:
requests.exceptions.RequestException: If the streaming connection fails
json.JSONDecodeError: If the streamed data is not valid JSON
"""
- url = self.client.base_url + "/2/likes/compliance/stream"
+ 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}"
@@ -735,6 +709,18 @@ def likes_compliance(
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 = {
"Accept": "application/json",
}
@@ -771,7 +757,7 @@ def likes_compliance(
# Parse JSON line
data = json.loads(line)
# Convert to response model if available
- yield LikesComplianceResponse.model_validate(data)
+ yield PostsResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON lines
continue
@@ -782,7 +768,7 @@ def likes_compliance(
if buffer.strip():
try:
data = json.loads(buffer.strip())
- yield LikesComplianceResponse.model_validate(data)
+ yield PostsResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON in final buffer
pass
@@ -792,32 +778,32 @@ def likes_compliance(
raise
- def labels_compliance(
+ def likes_compliance(
self,
backfill_minutes: int = None,
start_time: str = None,
end_time: str = None,
timeout: Optional[float] = None,
chunk_size: int = 1024,
- ) -> Generator[LabelsComplianceResponse, None, None]:
+ ) -> Generator[LikesComplianceResponse, None, None]:
"""
- Stream Post labels (Streaming)
- Streams all labeling events applied to Posts.
+ Stream Likes compliance data (Streaming)
+ Streams all compliance data related to Likes for Users.
This is a streaming endpoint that yields data in real-time as it becomes available.
Each yielded item represents a single data point from the stream.
Args:
backfill_minutes: The number of minutes of backfill requested.
- start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Post labels will be provided.
- end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp from which the Post labels will be provided.
+ start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Likes 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.
timeout: Request timeout in seconds (default: None for no timeout)
chunk_size: Size of chunks to read from the stream (default: 1024 bytes)
Yields:
- LabelsComplianceResponse: Individual streaming data items
+ LikesComplianceResponse: Individual streaming data items
Raises:
requests.exceptions.RequestException: If the streaming connection fails
json.JSONDecodeError: If the streamed data is not valid JSON
"""
- url = self.client.base_url + "/2/tweets/label/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}"
@@ -869,7 +855,7 @@ def labels_compliance(
# Parse JSON line
data = json.loads(line)
# Convert to response model if available
- yield LabelsComplianceResponse.model_validate(data)
+ yield LikesComplianceResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON lines
continue
@@ -880,7 +866,7 @@ def labels_compliance(
if buffer.strip():
try:
data = json.loads(buffer.strip())
- yield LabelsComplianceResponse.model_validate(data)
+ yield LikesComplianceResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON in final buffer
pass
@@ -890,46 +876,20 @@ def labels_compliance(
raise
- def posts_firehose_en(
- self,
- partition: int,
- backfill_minutes: int = None,
- start_time: str = None,
- end_time: str = None,
- tweetfields: List = None,
- expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
- timeout: Optional[float] = None,
- chunk_size: int = 1024,
- ) -> Generator[PostsFirehoseEnResponse, None, None]:
+ def get_rules(
+ self, ids: List = None, max_results: int = None, pagination_token: str = None
+ ) -> GetRulesResponse:
"""
- Stream English Posts (Streaming)
- Streams all public English-language Posts in real-time.
- This is a streaming endpoint that yields data in real-time as it becomes available.
- Each yielded item represents a single data point from the stream.
+ Get stream rules
+ Retrieves the active rule set or a subset of rules for the filtered stream.
Args:
- backfill_minutes: The number of minutes of backfill requested.
- partition: The partition number.
- start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided.
- end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided.
- tweetfields: A comma separated list of Tweet fields to display.
- expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
- timeout: Request timeout in seconds (default: None for no timeout)
- chunk_size: Size of chunks to read from the stream (default: 1024 bytes)
- Yields:
- PostsFirehoseEnResponse: Individual streaming data items
- Raises:
- requests.exceptions.RequestException: If the streaming connection fails
- json.JSONDecodeError: If the streamed data is not valid JSON
+ ids: A comma-separated list of Rule IDs.
+ max_results: The maximum number of results.
+ 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/firehose/stream/lang/en"
+ 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}"
@@ -939,28 +899,186 @@ def posts_firehose_en(
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 tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
- if expansions is not None:
- params["expansions"] = ",".join(str(item) for item in expansions)
- if mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
- headers = {
- "Accept": "application/json",
+ 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 = {}
+ # Prepare request data
+ json_data = None
+ # 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.
+ 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"
+ # Prepare request data
+ json_data = None
+ if body is not None:
+ json_data = (
+ body.model_dump(exclude_none=True)
+ if hasattr(body, "model_dump")
+ else body
+ )
+ # Make the request
+ response = self.client.session.post(
+ url,
+ params=params,
+ headers=headers,
+ json=json_data,
+ )
+ # 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_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 = {}
+ # Prepare request data
+ json_data = None
+ # 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 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,
+ timeout: Optional[float] = None,
+ chunk_size: int = 1024,
+ ) -> Generator[LikesSample10Response, None, None]:
+ """
+ Stream sampled Likes (Streaming)
+ Streams a 10% sample of public Likes in real-time.
+ This is a streaming endpoint that yields data in real-time as it becomes available.
+ Each yielded item represents a single data point from the stream.
+ Args:
+ backfill_minutes: The number of minutes of backfill requested.
+ partition: The partition number.
+ start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Likes will be provided.
+ end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided.
+ like_with_tweet_author_fields: A comma separated list of LikeWithTweetAuthor fields to display.
+ expansions: A comma separated list of fields to expand.
+ user_fields: A comma separated list of User fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
+ timeout: Request timeout in seconds (default: None for no timeout)
+ chunk_size: Size of chunks to read from the stream (default: 1024 bytes)
+ Yields:
+ LikesSample10Response: Individual streaming data items
+ Raises:
+ requests.exceptions.RequestException: If the streaming connection fails
+ json.JSONDecodeError: If the streamed data is not valid JSON
+ """
+ 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 = {
+ "Accept": "application/json",
}
# Prepare request data
json_data = None
@@ -995,7 +1113,7 @@ def posts_firehose_en(
# Parse JSON line
data = json.loads(line)
# Convert to response model if available
- yield PostsFirehoseEnResponse.model_validate(data)
+ yield LikesSample10Response.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON lines
continue
@@ -1006,7 +1124,7 @@ def posts_firehose_en(
if buffer.strip():
try:
data = json.loads(buffer.strip())
- yield PostsFirehoseEnResponse.model_validate(data)
+ yield LikesSample10Response.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON in final buffer
pass
@@ -1016,44 +1134,46 @@ def posts_firehose_en(
raise
- def posts(
+ def posts_firehose(
self,
+ partition: int,
backfill_minutes: int = None,
start_time: str = None,
end_time: str = None,
- tweetfields: List = None,
+ tweet_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
timeout: Optional[float] = None,
chunk_size: int = 1024,
- ) -> Generator[PostsResponse, None, None]:
+ ) -> Generator[PostsFirehoseResponse, None, None]:
"""
- Stream filtered Posts (Streaming)
- Streams Posts in real-time matching the active rule set.
+ Stream all Posts (Streaming)
+ Streams all public Posts in real-time.
This is a streaming endpoint that yields data in real-time as it becomes available.
Each yielded item represents a single data point from the stream.
Args:
backfill_minutes: The number of minutes of backfill requested.
- start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Posts will be provided.
+ partition: The partition number.
+ start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided.
end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided.
- tweetfields: A comma separated list of Tweet fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
timeout: Request timeout in seconds (default: None for no timeout)
chunk_size: Size of chunks to read from the stream (default: 1024 bytes)
Yields:
- PostsResponse: Individual streaming data items
+ PostsFirehoseResponse: Individual streaming data items
Raises:
requests.exceptions.RequestException: If the streaming connection fails
json.JSONDecodeError: If the streamed data is not valid JSON
"""
- url = self.client.base_url + "/2/tweets/search/stream"
+ 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}"
@@ -1065,22 +1185,24 @@ def 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 tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
+ 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 = {
"Accept": "application/json",
}
@@ -1117,7 +1239,7 @@ def posts(
# Parse JSON line
data = json.loads(line)
# Convert to response model if available
- yield PostsResponse.model_validate(data)
+ yield PostsFirehoseResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON lines
continue
@@ -1128,7 +1250,7 @@ def posts(
if buffer.strip():
try:
data = json.loads(buffer.strip())
- yield PostsResponse.model_validate(data)
+ yield PostsFirehoseResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON in final buffer
pass
@@ -1138,46 +1260,34 @@ def posts(
raise
- def posts_firehose_ko(
+ def users_compliance(
self,
partition: int,
backfill_minutes: int = None,
start_time: str = None,
end_time: str = None,
- tweetfields: List = None,
- expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
timeout: Optional[float] = None,
chunk_size: int = 1024,
- ) -> Generator[PostsFirehoseKoResponse, None, None]:
+ ) -> Generator[UsersComplianceResponse, None, None]:
"""
- Stream Korean Posts (Streaming)
- Streams all public Korean-language Posts in real-time.
+ Stream Users compliance data (Streaming)
+ Streams all compliance data related to Users.
This is a streaming endpoint that yields data in real-time as it becomes available.
Each yielded item represents a single data point from the stream.
Args:
backfill_minutes: The number of minutes of backfill requested.
partition: The partition number.
- start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided.
- end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided.
- tweetfields: A comma separated list of Tweet fields to display.
- expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
+ start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest 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 User Compliance events will be provided.
timeout: Request timeout in seconds (default: None for no timeout)
chunk_size: Size of chunks to read from the stream (default: 1024 bytes)
Yields:
- PostsFirehoseKoResponse: Individual streaming data items
+ UsersComplianceResponse: Individual streaming data items
Raises:
requests.exceptions.RequestException: If the streaming connection fails
json.JSONDecodeError: If the streamed data is not valid JSON
"""
- 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}"
@@ -1195,18 +1305,6 @@ def posts_firehose_ko(
params["start_time"] = start_time
if end_time is not None:
params["end_time"] = end_time
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
- if expansions is not None:
- params["expansions"] = ",".join(str(item) for item in expansions)
- if mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
headers = {
"Accept": "application/json",
}
@@ -1243,7 +1341,7 @@ def posts_firehose_ko(
# Parse JSON line
data = json.loads(line)
# Convert to response model if available
- yield PostsFirehoseKoResponse.model_validate(data)
+ yield UsersComplianceResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON lines
continue
@@ -1254,7 +1352,7 @@ def posts_firehose_ko(
if buffer.strip():
try:
data = json.loads(buffer.strip())
- yield PostsFirehoseKoResponse.model_validate(data)
+ yield UsersComplianceResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON in final buffer
pass
@@ -1264,42 +1362,34 @@ def posts_firehose_ko(
raise
- def likes_sample10(
+ def posts_compliance(
self,
partition: int,
backfill_minutes: int = None,
start_time: str = None,
end_time: str = None,
- like_with_tweet_authorfields: List = None,
- expansions: List = None,
- userfields: List = None,
- tweetfields: List = None,
timeout: Optional[float] = None,
chunk_size: int = 1024,
- ) -> Generator[LikesSample10Response, None, None]:
+ ) -> Generator[PostsComplianceResponse, None, None]:
"""
- Stream sampled Likes (Streaming)
- Streams a 10% sample of public Likes in real-time.
+ Stream Posts compliance data (Streaming)
+ Streams all compliance data related to Posts.
This is a streaming endpoint that yields data in real-time as it becomes available.
Each yielded item represents a single data point from the stream.
Args:
backfill_minutes: The number of minutes of backfill requested.
partition: The partition number.
- start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Likes will be provided.
- end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided.
- like_with_tweet_authorfields: A comma separated list of LikeWithTweetAuthor fields to display.
- expansions: A comma separated list of fields to expand.
- userfields: A comma separated list of User fields to display.
- tweetfields: A comma separated list of Tweet fields to display.
+ start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Post Compliance events will be provided.
+ end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Post Compliance events will be provided.
timeout: Request timeout in seconds (default: None for no timeout)
chunk_size: Size of chunks to read from the stream (default: 1024 bytes)
Yields:
- LikesSample10Response: Individual streaming data items
+ PostsComplianceResponse: Individual streaming data items
Raises:
requests.exceptions.RequestException: If the streaming connection fails
json.JSONDecodeError: If the streamed data is not valid JSON
"""
- url = self.client.base_url + "/2/likes/sample10/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}"
@@ -1317,16 +1407,6 @@ def likes_sample10(
params["start_time"] = start_time
if end_time is not None:
params["end_time"] = end_time
- if like_with_tweet_authorfields is not None:
- params["like_with_tweet_author.fields"] = ",".join(
- str(item) for item in like_with_tweet_authorfields
- )
- if expansions is not None:
- params["expansions"] = ",".join(str(item) for item in expansions)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
headers = {
"Accept": "application/json",
}
@@ -1363,7 +1443,7 @@ def likes_sample10(
# Parse JSON line
data = json.loads(line)
# Convert to response model if available
- yield LikesSample10Response.model_validate(data)
+ yield PostsComplianceResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON lines
continue
@@ -1374,7 +1454,7 @@ def likes_sample10(
if buffer.strip():
try:
data = json.loads(buffer.strip())
- yield LikesSample10Response.model_validate(data)
+ yield PostsComplianceResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON in final buffer
pass
@@ -1384,34 +1464,46 @@ def likes_sample10(
raise
- def posts_compliance(
+ def 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,
timeout: Optional[float] = None,
chunk_size: int = 1024,
- ) -> Generator[PostsComplianceResponse, None, None]:
+ ) -> Generator[PostsSample10Response, None, None]:
"""
- Stream Posts compliance data (Streaming)
- Streams all compliance data related to Posts.
+ Stream 10% sampled Posts (Streaming)
+ Streams a 10% sample of public Posts in real-time.
This is a streaming endpoint that yields data in real-time as it becomes available.
Each yielded item represents a single data point from the stream.
Args:
backfill_minutes: The number of minutes of backfill requested.
partition: The partition number.
- start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp from which the Post Compliance events will be provided.
- end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Post Compliance events will be provided.
+ start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided.
+ end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided.
+ tweet_fields: A comma separated list of Tweet fields to display.
+ expansions: A comma separated list of fields to expand.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
timeout: Request timeout in seconds (default: None for no timeout)
chunk_size: Size of chunks to read from the stream (default: 1024 bytes)
Yields:
- PostsComplianceResponse: Individual streaming data items
+ PostsSample10Response: Individual streaming data items
Raises:
requests.exceptions.RequestException: If the streaming connection fails
json.JSONDecodeError: If the streamed data is not valid JSON
"""
- url = self.client.base_url + "/2/tweets/compliance/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}"
@@ -1429,6 +1521,18 @@ def posts_compliance(
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 = {
"Accept": "application/json",
}
@@ -1465,7 +1569,7 @@ def posts_compliance(
# Parse JSON line
data = json.loads(line)
# Convert to response model if available
- yield PostsComplianceResponse.model_validate(data)
+ yield PostsSample10Response.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON lines
continue
@@ -1476,7 +1580,7 @@ def posts_compliance(
if buffer.strip():
try:
data = json.loads(buffer.strip())
- yield PostsComplianceResponse.model_validate(data)
+ yield PostsSample10Response.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON in final buffer
pass
@@ -1486,122 +1590,24 @@ def posts_compliance(
raise
- 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.
- max_results: The maximum number of results.
- 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 = {}
- # Prepare request data
- json_data = None
- # 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.
- 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"
- # Prepare request data
- json_data = None
- if body is not None:
- json_data = (
- body.model_dump(exclude_none=True)
- if hasattr(body, "model_dump")
- else body
- )
- # Make the request
- response = self.client.session.post(
- url,
- params=params,
- headers=headers,
- json=json_data,
- )
- # 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 posts_firehose_ja(
+ def posts_firehose_en(
self,
partition: int,
backfill_minutes: int = None,
start_time: str = None,
end_time: str = None,
- tweetfields: List = None,
+ tweet_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
timeout: Optional[float] = None,
chunk_size: int = 1024,
- ) -> Generator[PostsFirehoseJaResponse, None, None]:
+ ) -> Generator[PostsFirehoseEnResponse, None, None]:
"""
- Stream Japanese Posts (Streaming)
- Streams all public Japanese-language Posts in real-time.
+ Stream English Posts (Streaming)
+ Streams all public English-language Posts in real-time.
This is a streaming endpoint that yields data in real-time as it becomes available.
Each yielded item represents a single data point from the stream.
Args:
@@ -1609,21 +1615,21 @@ def posts_firehose_ja(
partition: The partition number.
start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Posts will be provided.
end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided.
- tweetfields: A comma separated list of Tweet fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
timeout: Request timeout in seconds (default: None for no timeout)
chunk_size: Size of chunks to read from the stream (default: 1024 bytes)
Yields:
- PostsFirehoseJaResponse: Individual streaming data items
+ PostsFirehoseEnResponse: Individual streaming data items
Raises:
requests.exceptions.RequestException: If the streaming connection fails
json.JSONDecodeError: If the streamed data is not valid JSON
"""
- url = self.client.base_url + "/2/tweets/firehose/stream/lang/ja"
+ 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}"
@@ -1641,18 +1647,18 @@ def posts_firehose_ja(
params["start_time"] = start_time
if end_time is not None:
params["end_time"] = end_time
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
+ 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 = {
"Accept": "application/json",
}
@@ -1689,7 +1695,7 @@ def posts_firehose_ja(
# Parse JSON line
data = json.loads(line)
# Convert to response model if available
- yield PostsFirehoseJaResponse.model_validate(data)
+ yield PostsFirehoseEnResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON lines
continue
@@ -1700,7 +1706,7 @@ def posts_firehose_ja(
if buffer.strip():
try:
data = json.loads(buffer.strip())
- yield PostsFirehoseJaResponse.model_validate(data)
+ yield PostsFirehoseEnResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON in final buffer
pass
@@ -1710,42 +1716,40 @@ def posts_firehose_ja(
raise
- def likes_firehose(
+ def posts_sample(
self,
- partition: int,
backfill_minutes: int = None,
- start_time: str = None,
- end_time: str = None,
- like_with_tweet_authorfields: List = None,
+ tweet_fields: List = None,
expansions: List = None,
- userfields: List = None,
- tweetfields: List = None,
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
timeout: Optional[float] = None,
chunk_size: int = 1024,
- ) -> Generator[LikesFirehoseResponse, None, None]:
+ ) -> Generator[PostsSampleResponse, None, None]:
"""
- Stream all Likes (Streaming)
- Streams all public Likes in real-time.
+ Stream sampled Posts (Streaming)
+ Streams a 1% sample of public Posts in real-time.
This is a streaming endpoint that yields data in real-time as it becomes available.
Each yielded item represents a single data point from the stream.
Args:
backfill_minutes: The number of minutes of backfill requested.
- partition: The partition number.
- start_time: YYYY-MM-DDTHH:mm:ssZ. The earliest UTC timestamp to which the Likes will be provided.
- end_time: YYYY-MM-DDTHH:mm:ssZ. The latest UTC timestamp to which the Posts will be provided.
- like_with_tweet_authorfields: A comma separated list of LikeWithTweetAuthor fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
expansions: A comma separated list of fields to expand.
- userfields: A comma separated list of User fields to display.
- tweetfields: A comma separated list of Tweet fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
timeout: Request timeout in seconds (default: None for no timeout)
chunk_size: Size of chunks to read from the stream (default: 1024 bytes)
Yields:
- LikesFirehoseResponse: Individual streaming data items
+ PostsSampleResponse: Individual streaming data items
Raises:
requests.exceptions.RequestException: If the streaming connection fails
json.JSONDecodeError: If the streamed data is not valid JSON
"""
- url = self.client.base_url + "/2/likes/firehose/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}"
@@ -1757,22 +1761,18 @@ def likes_firehose(
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_authorfields is not None:
- params["like_with_tweet_author.fields"] = ",".join(
- str(item) for item in like_with_tweet_authorfields
- )
+ 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 userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 = {
"Accept": "application/json",
}
@@ -1809,7 +1809,7 @@ def likes_firehose(
# Parse JSON line
data = json.loads(line)
# Convert to response model if available
- yield LikesFirehoseResponse.model_validate(data)
+ yield PostsSampleResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON lines
continue
@@ -1820,7 +1820,7 @@ def likes_firehose(
if buffer.strip():
try:
data = json.loads(buffer.strip())
- yield LikesFirehoseResponse.model_validate(data)
+ yield PostsSampleResponse.model_validate(data)
except json.JSONDecodeError:
# Skip invalid JSON in final buffer
pass
diff --git a/xdk/python/xdk/stream/models.py b/xdk/python/xdk/stream/models.py
index d1bd57c0..ca5287bc 100644
--- a/xdk/python/xdk/stream/models.py
+++ b/xdk/python/xdk/stream/models.py
@@ -16,56 +16,56 @@
from datetime import datetime
-# Models for posts_sample
+# Models for likes_firehose
-class PostsSampleResponse(BaseModel):
- """Response model for posts_sample"""
+class LikesFirehoseResponse(BaseModel):
+ """Response model for likes_firehose"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_rule_counts
+# Models for posts_firehose_pt
-class GetRuleCountsResponse(BaseModel):
- """Response model for get_rule_counts"""
+class PostsFirehosePtResponse(BaseModel):
+ """Response model for posts_firehose_pt"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for posts_firehose
+# Models for posts_firehose_ja
-class PostsFirehoseResponse(BaseModel):
- """Response model for posts_firehose"""
+class PostsFirehoseJaResponse(BaseModel):
+ """Response model for posts_firehose_ja"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for posts_firehose_pt
+# Models for labels_compliance
-class PostsFirehosePtResponse(BaseModel):
- """Response model for posts_firehose_pt"""
+class LabelsComplianceResponse(BaseModel):
+ """Response model for labels_compliance"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for users_compliance
+# Models for posts_firehose_ko
-class UsersComplianceResponse(BaseModel):
- """Response model for users_compliance"""
+class PostsFirehoseKoResponse(BaseModel):
+ """Response model for posts_firehose_ko"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for posts_sample10
+# Models for posts
-class PostsSample10Response(BaseModel):
- """Response model for posts_sample10"""
+class PostsResponse(BaseModel):
+ """Response model for posts"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
@@ -79,38 +79,35 @@ class LikesComplianceResponse(BaseModel):
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for labels_compliance
+# Models for get_rules
-class LabelsComplianceResponse(BaseModel):
- """Response model for labels_compliance"""
+class GetRulesResponse(BaseModel):
+ """Response model for get_rules"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for posts_firehose_en
-
-
-class PostsFirehoseEnResponse(BaseModel):
- """Response model for posts_firehose_en"""
+# Models for update_rules
- model_config = ConfigDict(populate_by_name=True, extra="allow")
+class UpdateRulesRequest(BaseModel):
+ """Request model for update_rules"""
-# Models for posts
+ model_config = ConfigDict(populate_by_name=True)
-class PostsResponse(BaseModel):
- """Response model for posts"""
+class UpdateRulesResponse(BaseModel):
+ """Response model for update_rules"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for posts_firehose_ko
+# Models for get_rule_counts
-class PostsFirehoseKoResponse(BaseModel):
- """Response model for posts_firehose_ko"""
+class GetRuleCountsResponse(BaseModel):
+ """Response model for get_rule_counts"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
@@ -124,52 +121,55 @@ class LikesSample10Response(BaseModel):
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for posts_compliance
+# Models for posts_firehose
-class PostsComplianceResponse(BaseModel):
- """Response model for posts_compliance"""
+class PostsFirehoseResponse(BaseModel):
+ """Response model for posts_firehose"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_rules
+# Models for users_compliance
-class GetRulesResponse(BaseModel):
- """Response model for get_rules"""
+class UsersComplianceResponse(BaseModel):
+ """Response model for users_compliance"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for update_rules
+# Models for posts_compliance
-class UpdateRulesRequest(BaseModel):
- """Request model for update_rules"""
+class PostsComplianceResponse(BaseModel):
+ """Response model for posts_compliance"""
- model_config = ConfigDict(populate_by_name=True)
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
-class UpdateRulesResponse(BaseModel):
- """Response model for update_rules"""
+# Models for posts_sample10
+
+
+class PostsSample10Response(BaseModel):
+ """Response model for posts_sample10"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for posts_firehose_ja
+# Models for posts_firehose_en
-class PostsFirehoseJaResponse(BaseModel):
- """Response model for posts_firehose_ja"""
+class PostsFirehoseEnResponse(BaseModel):
+ """Response model for posts_firehose_en"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for likes_firehose
+# Models for posts_sample
-class LikesFirehoseResponse(BaseModel):
- """Response model for likes_firehose"""
+class PostsSampleResponse(BaseModel):
+ """Response model for posts_sample"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
diff --git a/xdk/python/xdk/trends/client.py b/xdk/python/xdk/trends/client.py
index 92a1af97..3c4947b8 100644
--- a/xdk/python/xdk/trends/client.py
+++ b/xdk/python/xdk/trends/client.py
@@ -21,8 +21,9 @@
if TYPE_CHECKING:
from ..client import Client
from .models import (
- GetPersonalizedResponse,
+ GetAiResponse,
GetByWoeidResponse,
+ GetPersonalizedResponse,
)
@@ -34,54 +35,48 @@ def __init__(self, client: Client):
self.client = client
- def get_personalized(
- self, personalized_trendfields: List = None
- ) -> GetPersonalizedResponse:
+ def get_ai(self, id: Any, news_fields: List = None) -> GetAiResponse:
"""
- Get personalized Trends
- Retrieves personalized trending topics for the authenticated user.
+ Get AI Trends by ID
+ Retrieves an AI trend by its ID.
Args:
- personalized_trendfields: A comma separated list of PersonalizedTrend fields to display.
+ id: The ID of the ai trend.
+ news_fields: A comma separated list of News fields to display.
Returns:
- GetPersonalizedResponse: Response data
+ GetAiResponse: 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_trendfields is not None:
- params["personalized_trend.fields"] = ",".join(
- str(item) for item in personalized_trendfields
+ url = self.client.base_url + "/2/ai_trends/{id}"
+ url = url.replace("{id}", str(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 news_fields is not None:
+ params["news.fields"] = ",".join(str(item) for item in news_fields)
headers = {}
# Prepare request data
json_data = None
# 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 GetPersonalizedResponse.model_validate(response_data)
+ return GetAiResponse.model_validate(response_data)
def get_by_woeid(
- self, woeid: int, max_trends: int = None, trendfields: List = None
+ self, woeid: int, max_trends: int = None, trend_fields: List = None
) -> GetByWoeidResponse:
"""
Get Trends by WOEID
@@ -89,7 +84,7 @@ def get_by_woeid(
Args:
woeid: The WOEID of the place to lookup a trend for.
max_trends: The maximum number of results.
- trendfields: A comma separated list of Trend fields to display.
+ trend_fields: A comma separated list of Trend fields to display.
Returns:
GetByWoeidResponse: Response data
"""
@@ -106,8 +101,8 @@ def get_by_woeid(
params = {}
if max_trends is not None:
params["max_trends"] = max_trends
- if trendfields is not None:
- params["trend.fields"] = ",".join(str(item) for item in trendfields)
+ if trend_fields is not None:
+ params["trend.fields"] = ",".join(str(item) for item in trend_fields)
headers = {}
# Prepare request data
json_data = None
@@ -123,3 +118,49 @@ def get_by_woeid(
response_data = response.json()
# Convert to Pydantic model if applicable
return GetByWoeidResponse.model_validate(response_data)
+
+
+ def get_personalized(
+ self, personalized_trend_fields: List = None
+ ) -> GetPersonalizedResponse:
+ """
+ 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:
+ 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 = {}
+ if personalized_trend_fields is not None:
+ params["personalized_trend.fields"] = ",".join(
+ str(item) for item in personalized_trend_fields
+ )
+ headers = {}
+ # Prepare request data
+ json_data = None
+ # 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 65f38c6d..f5a2a8ce 100644
--- a/xdk/python/xdk/trends/models.py
+++ b/xdk/python/xdk/trends/models.py
@@ -16,11 +16,11 @@
from datetime import datetime
-# Models for get_personalized
+# Models for get_ai
-class GetPersonalizedResponse(BaseModel):
- """Response model for get_personalized"""
+class GetAiResponse(BaseModel):
+ """Response model for get_ai"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
@@ -32,3 +32,12 @@ class GetByWoeidResponse(BaseModel):
"""Response model for get_by_woeid"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
+
+
+# Models for get_personalized
+
+
+class GetPersonalizedResponse(BaseModel):
+ """Response model for get_personalized"""
+
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
diff --git a/xdk/python/xdk/usage/client.py b/xdk/python/xdk/usage/client.py
index bad751eb..a478bc8e 100644
--- a/xdk/python/xdk/usage/client.py
+++ b/xdk/python/xdk/usage/client.py
@@ -33,13 +33,13 @@ def __init__(self, client: Client):
self.client = client
- def get(self, days: int = None, usagefields: List = None) -> GetResponse:
+ def get(self, days: int = None, usage_fields: List = None) -> 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.
- usagefields: A comma separated list of Usage fields to display.
+ usage_fields: A comma separated list of Usage fields to display.
Returns:
GetResponse: Response data
"""
@@ -55,8 +55,8 @@ def get(self, days: int = None, usagefields: List = None) -> GetResponse:
params = {}
if days is not None:
params["days"] = days
- if usagefields is not None:
- params["usage.fields"] = ",".join(str(item) for item in usagefields)
+ if usage_fields is not None:
+ params["usage.fields"] = ",".join(str(item) for item in usage_fields)
headers = {}
# Prepare request data
json_data = None
diff --git a/xdk/python/xdk/users/client.py b/xdk/python/xdk/users/client.py
index da7588db..57e1abd7 100644
--- a/xdk/python/xdk/users/client.py
+++ b/xdk/python/xdk/users/client.py
@@ -21,51 +21,51 @@
if TYPE_CHECKING:
from ..client import Client
from .models import (
- GetMeResponse,
- UnfollowListResponse,
+ LikePostRequest,
+ LikePostResponse,
+ UnlikePostResponse,
GetMutingResponse,
MuteUserRequest,
MuteUserResponse,
- UnlikePostResponse,
- GetPostsResponse,
- GetFollowingResponse,
- FollowUserRequest,
- FollowUserResponse,
- GetTimelineResponse,
+ GetPinnedListsResponse,
+ PinListRequest,
+ PinListResponse,
+ UnrepostPostResponse,
UnmuteUserResponse,
- SearchResponse,
- GetOwnedListsResponse,
- GetByUsernamesResponse,
- GetMentionsResponse,
+ DeleteBookmarkResponse,
GetListMembershipsResponse,
- GetBlockingResponse,
+ GetMeResponse,
+ GetLikedPostsResponse,
+ GetPostsResponse,
GetFollowedListsResponse,
FollowListRequest,
FollowListResponse,
- UnrepostPostResponse,
- GetRepostsOfMeResponse,
- GetBookmarksResponse,
- CreateBookmarkRequest,
- CreateBookmarkResponse,
- GetByIdsResponse,
- GetByIdResponse,
- GetBookmarkFoldersResponse,
- UnblockDmsResponse,
- GetPinnedListsResponse,
- PinListRequest,
- PinListResponse,
- GetLikedPostsResponse,
- GetBookmarksByFolderIdResponse,
- LikePostRequest,
- LikePostResponse,
- UnpinListResponse,
GetByUsernameResponse,
- DeleteBookmarkResponse,
- BlockDmsResponse,
+ GetMentionsResponse,
+ GetOwnedListsResponse,
RepostPostRequest,
RepostPostResponse,
+ UnfollowListResponse,
+ GetByIdsResponse,
+ GetBookmarksByFolderIdResponse,
+ UnblockDmsResponse,
+ GetBlockingResponse,
+ GetByUsernamesResponse,
UnfollowUserResponse,
+ BlockDmsResponse,
GetFollowersResponse,
+ GetByIdResponse,
+ GetBookmarkFoldersResponse,
+ GetFollowingResponse,
+ FollowUserRequest,
+ FollowUserResponse,
+ GetTimelineResponse,
+ SearchResponse,
+ GetBookmarksResponse,
+ CreateBookmarkRequest,
+ CreateBookmarkResponse,
+ GetRepostsOfMeResponse,
+ UnpinListResponse,
)
@@ -77,69 +77,72 @@ def __init__(self, client: Client):
self.client = client
- def get_me(
- self, userfields: List = None, expansions: List = None, tweetfields: List = None
- ) -> GetMeResponse:
+ def like_post(
+ self, id: Any, body: Optional[LikePostRequest] = None
+ ) -> LikePostResponse:
"""
- Get my User
- Retrieves details of the authenticated user.
+ Like Post
+ Causes the authenticated user to Like a specific Post by its ID.
Args:
- userfields: A comma separated list of User fields to display.
- expansions: A comma separated list of fields to expand.
- tweetfields: A comma separated list of Tweet fields to display.
- Returns:
- GetMeResponse: Response data
+ 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/me"
+ url = self.client.base_url + "/2/users/{id}/likes"
+ url = url.replace("{id}", str(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 userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if expansions is not None:
- params["expansions"] = ",".join(str(item) for item in expansions)
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
headers = {}
+ headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
+ if body is not None:
+ json_data = (
+ body.model_dump(exclude_none=True)
+ if hasattr(body, "model_dump")
+ else body
+ )
# 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=json_data,
)
else:
- response = self.client.session.get(
+ response = self.client.session.post(
url,
params=params,
headers=headers,
+ json=json_data,
)
# Check for errors
response.raise_for_status()
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetMeResponse.model_validate(response_data)
+ return LikePostResponse.model_validate(response_data)
- def unfollow_list(self, id: Any, list_id: Any) -> UnfollowListResponse:
+ def unlike_post(self, id: Any, tweet_id: Any) -> UnlikePostResponse:
"""
- Unfollow List
- Causes the authenticated user to unfollow a specific List by its ID.
+ Unlike Post
+ Causes the authenticated user to Unlike a specific Post by its ID.
Args:
- id: The ID of the authenticated source User that will unfollow the List.
- list_id: The ID of the List to unfollow.
+ id: The ID of the authenticated source User that is requesting to unlike the Post.
+ tweet_id: The ID of the Post that the User is requesting to unlike.
Returns:
- UnfollowListResponse: Response data
+ UnlikePostResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/followed_lists/{list_id}"
+ url = self.client.base_url + "/2/users/{id}/likes/{tweet_id}"
url = url.replace("{id}", str(id))
- url = url.replace("{list_id}", str(list_id))
+ url = url.replace("{tweet_id}", str(tweet_id))
# Ensure we have a valid access token
if self.client.oauth2_auth and self.client.token:
# Check if token needs refresh
@@ -167,7 +170,7 @@ def unfollow_list(self, id: Any, list_id: Any) -> UnfollowListResponse:
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return UnfollowListResponse.model_validate(response_data)
+ return UnlikePostResponse.model_validate(response_data)
def get_muting(
@@ -175,9 +178,9 @@ def get_muting(
id: Any,
max_results: int = None,
pagination_token: Any = None,
- userfields: List = None,
+ user_fields: List = None,
expansions: List = None,
- tweetfields: List = None,
+ tweet_fields: List = None,
) -> GetMutingResponse:
"""
Get muting
@@ -186,9 +189,9 @@ def get_muting(
id: The ID of the authenticated source User for whom to return results.
max_results: The maximum number of results.
pagination_token: This parameter is used to get the next 'page' of results.
- userfields: A comma separated list of User fields to display.
+ user_fields: A comma separated list of User fields to display.
expansions: A comma separated list of fields to expand.
- tweetfields: A comma separated list of Tweet fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
Returns:
GetMutingResponse: Response data
"""
@@ -204,12 +207,12 @@ def get_muting(
params["max_results"] = max_results
if pagination_token is not None:
params["pagination_token"] = pagination_token
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
+ 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 tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ if tweet_fields is not None:
+ params["tweet.fields"] = ",".join(str(item) for item in tweet_fields)
headers = {}
# Prepare request data
json_data = None
@@ -287,37 +290,50 @@ def mute_user(
return MuteUserResponse.model_validate(response_data)
- def unlike_post(self, id: Any, tweet_id: Any) -> UnlikePostResponse:
+ def get_pinned_lists(
+ self,
+ id: Any,
+ list_fields: List = None,
+ expansions: List = None,
+ user_fields: List = None,
+ ) -> GetPinnedListsResponse:
"""
- Unlike Post
- Causes the authenticated user to Unlike a specific Post by its ID.
+ Get pinned Lists
+ Retrieves a list of Lists pinned by the authenticated user.
Args:
- id: The ID of the authenticated source User that is requesting to unlike the Post.
- tweet_id: The ID of the Post that the User is requesting to unlike.
+ id: The ID of the authenticated source User for whom to return results.
+ list_fields: A comma separated list of List fields to display.
+ expansions: A comma separated list of fields to expand.
+ user_fields: A comma separated list of User fields to display.
Returns:
- UnlikePostResponse: Response data
+ GetPinnedListsResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/likes/{tweet_id}"
+ url = self.client.base_url + "/2/users/{id}/pinned_lists"
url = url.replace("{id}", str(id))
- url = url.replace("{tweet_id}", str(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 = {}
+ 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)
headers = {}
# Prepare request data
json_data = None
# 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,
@@ -327,185 +343,161 @@ def unlike_post(self, id: Any, tweet_id: Any) -> UnlikePostResponse:
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return UnlikePostResponse.model_validate(response_data)
+ return GetPinnedListsResponse.model_validate(response_data)
- def get_posts(
- self,
- 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,
- tweetfields: List = None,
- expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
- ) -> GetPostsResponse:
+ def pin_list(self, id: Any, body: PinListRequest) -> PinListResponse:
"""
- Get Posts
- Retrieves a list of posts authored by a specific User by their ID.
+ Pin List
+ Causes the authenticated user to pin a specific List by its ID.
Args:
- id: The ID of the User to lookup.
- since_id: The minimum Post ID to be included in the result set. This parameter takes precedence over start_time if both are specified.
- until_id: The maximum Post ID to be included in the result set. This parameter takes precedence over end_time if both are specified.
- max_results: The maximum number of results.
- pagination_token: This parameter is used to get the next 'page' of results.
- exclude: The set of entities to exclude (e.g. 'replies' or 'retweets').
- 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.
- 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.
- tweetfields: A comma separated list of Tweet fields to display.
- expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
- Returns:
- GetPostsResponse: Response data
+ 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}/tweets"
+ url = self.client.base_url + "/2/users/{id}/pinned_lists"
url = url.replace("{id}", str(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 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 tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
- if expansions is not None:
- params["expansions"] = ",".join(str(item) for item in expansions)
- if mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
headers = {}
+ headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
+ if body is not None:
+ json_data = (
+ body.model_dump(exclude_none=True)
+ if hasattr(body, "model_dump")
+ else body
+ )
# 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=json_data,
+ )
+ else:
+ response = self.client.session.post(
+ url,
+ params=params,
+ headers=headers,
+ json=json_data,
+ )
# 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)
+ return PinListResponse.model_validate(response_data)
- def get_following(
- self,
- id: Any,
- max_results: int = None,
- pagination_token: Any = None,
- userfields: List = None,
- expansions: List = None,
- tweetfields: List = None,
- ) -> GetFollowingResponse:
+ def unrepost_post(self, id: Any, source_tweet_id: Any) -> UnrepostPostResponse:
"""
- Get following
- Retrieves a list of Users followed by a specific User by their ID.
+ Unrepost Post
+ Causes the authenticated user to unrepost a specific Post by its ID.
Args:
- id: The ID of the User to lookup.
- max_results: The maximum number of results.
- pagination_token: This parameter is used to get a specified 'page' of results.
- userfields: A comma separated list of User fields to display.
- expansions: A comma separated list of fields to expand.
- tweetfields: A comma separated list of Tweet fields to display.
+ id: The ID of the authenticated source User that is requesting to repost the Post.
+ source_tweet_id: The ID of the Post that the User is requesting to unretweet.
Returns:
- GetFollowingResponse: Response data
+ UnrepostPostResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/following"
+ url = self.client.base_url + "/2/users/{id}/retweets/{source_tweet_id}"
url = url.replace("{id}", str(id))
- if self.client.bearer_token:
- self.client.session.headers["Authorization"] = (
- f"Bearer {self.client.bearer_token}"
+ url = url.replace("{source_tweet_id}", str(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 = {}
+ headers = {}
+ # Prepare request data
+ json_data = None
+ # Make the request
+ if self.client.oauth2_session:
+ response = self.client.oauth2_session.delete(
+ url,
+ params=params,
+ headers=headers,
)
- elif self.client.access_token:
- self.client.session.headers["Authorization"] = (
- f"Bearer {self.client.access_token}"
+ 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 unmute_user(
+ self, source_user_id: Any, target_user_id: Any
+ ) -> 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.
+ 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}"
+ url = url.replace("{source_user_id}", str(source_user_id))
+ url = url.replace("{target_user_id}", str(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 = {}
- if max_results is not None:
- params["max_results"] = max_results
- if pagination_token is not None:
- params["pagination_token"] = pagination_token
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if expansions is not None:
- params["expansions"] = ",".join(str(item) for item in expansions)
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
headers = {}
# Prepare request data
json_data = None
# Make the request
- response = self.client.session.get(
- url,
- params=params,
- headers=headers,
- )
+ 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 GetFollowingResponse.model_validate(response_data)
+ return UnmuteUserResponse.model_validate(response_data)
- def follow_user(
- self, id: Any, body: Optional[FollowUserRequest] = None
- ) -> FollowUserResponse:
+ def delete_bookmark(self, id: Any, tweet_id: Any) -> DeleteBookmarkResponse:
"""
- Follow User
- Causes the authenticated user to follow a specific user by their ID.
+ Delete Bookmark
+ Removes a Post from the authenticated user’s Bookmarks by its 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
+ id: The ID of the authenticated source User whose bookmark is to be removed.
+ tweet_id: The ID of the Post that the source User is removing from bookmarks.
+ Returns:
+ DeleteBookmarkResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/following"
+ url = self.client.base_url + "/2/users/{id}/bookmarks/{tweet_id}"
url = url.replace("{id}", str(id))
+ url = url.replace("{tweet_id}", str(tweet_id))
# Ensure we have a valid access token
if self.client.oauth2_auth and self.client.token:
# Check if token needs refresh
@@ -513,167 +505,135 @@ def follow_user(
self.client.refresh_token()
params = {}
headers = {}
- headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
- if body is not None:
- json_data = (
- body.model_dump(exclude_none=True)
- if hasattr(body, "model_dump")
- else body
- )
# 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=json_data,
)
else:
- response = self.client.session.post(
+ response = self.client.session.delete(
url,
params=params,
headers=headers,
- json=json_data,
)
# 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 DeleteBookmarkResponse.model_validate(response_data)
- def get_timeline(
+ def get_list_memberships(
self,
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,
- tweetfields: List = None,
+ list_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
- ) -> GetTimelineResponse:
+ user_fields: List = None,
+ ) -> GetListMembershipsResponse:
"""
- Get Timeline
- Retrieves a reverse chronological list of Posts in the authenticated User’s Timeline.
+ 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 to list Reverse Chronological Timeline Posts of.
- since_id: The minimum Post ID to be included in the result set. This parameter takes precedence over start_time if both are specified.
- until_id: The maximum Post ID to be included in the result set. This parameter takes precedence over end_time if both are specified.
+ id: The ID of the User to lookup.
max_results: The maximum number of results.
- pagination_token: This parameter is used to get the next 'page' of results.
- exclude: The set of entities to exclude (e.g. 'replies' or 'retweets').
- 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.
- 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.
- tweetfields: A comma separated list of Tweet fields to display.
+ pagination_token: This parameter is used to get a specified 'page' of results.
+ list_fields: A comma separated list of List fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
+ user_fields: A comma separated list of User fields to display.
Returns:
- GetTimelineResponse: Response data
+ GetListMembershipsResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/timelines/reverse_chronological"
+ url = self.client.base_url + "/2/users/{id}/list_memberships"
url = url.replace("{id}", str(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 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 tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
+ if user_fields is not None:
+ params["user.fields"] = ",".join(str(item) for item in user_fields)
headers = {}
# Prepare request data
json_data = None
# 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 GetTimelineResponse.model_validate(response_data)
+ return GetListMembershipsResponse.model_validate(response_data)
- def unmute_user(
- self, source_user_id: Any, target_user_id: Any
- ) -> UnmuteUserResponse:
+ def get_me(
+ self,
+ user_fields: List = None,
+ expansions: List = None,
+ tweet_fields: List = None,
+ ) -> GetMeResponse:
"""
- Unmute User
- Causes the authenticated user to unmute a specific user by their ID.
+ Get my User
+ Retrieves details of the authenticated user.
Args:
- source_user_id: The ID of the authenticated source User that is requesting to unmute the target User.
- target_user_id: The ID of the User that the source User is requesting to unmute.
+ user_fields: A comma separated list of User fields to display.
+ expansions: A comma separated list of fields to expand.
+ tweet_fields: A comma separated list of Tweet fields to display.
Returns:
- UnmuteUserResponse: Response data
+ GetMeResponse: Response data
"""
- url = self.client.base_url + "/2/users/{source_user_id}/muting/{target_user_id}"
- url = url.replace("{source_user_id}", str(source_user_id))
- url = url.replace("{target_user_id}", str(target_user_id))
+ 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 = {}
# Prepare request data
json_data = None
# 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,
@@ -683,50 +643,61 @@ def unmute_user(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return UnmuteUserResponse.model_validate(response_data)
+ return GetMeResponse.model_validate(response_data)
- def search(
+ def get_liked_posts(
self,
- query: Any,
+ id: Any,
max_results: int = None,
- next_token: Any = None,
- userfields: List = None,
+ pagination_token: Any = None,
+ tweet_fields: List = None,
expansions: List = None,
- tweetfields: List = None,
- ) -> SearchResponse:
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
+ ) -> GetLikedPostsResponse:
"""
- Search Users
- Retrieves a list of Users matching a search query.
+ Get liked Posts
+ Retrieves a list of Posts liked 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.
max_results: The maximum number of results.
- 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.
- userfields: A comma separated list of User fields to display.
+ pagination_token: This parameter is used to get the next 'page' of results.
+ tweet_fields: A comma separated list of Tweet fields to display.
expansions: A comma separated list of fields to expand.
- tweetfields: A comma separated list of Tweet fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
Returns:
- SearchResponse: Response data
+ GetLikedPostsResponse: Response data
"""
- url = self.client.base_url + "/2/users/search"
+ url = self.client.base_url + "/2/users/{id}/liked_tweets"
+ url = url.replace("{id}", str(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 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 userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
+ 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 tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 = {}
# Prepare request data
json_data = None
@@ -748,32 +719,48 @@ def search(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return SearchResponse.model_validate(response_data)
+ return GetLikedPostsResponse.model_validate(response_data)
- def get_owned_lists(
+ def get_posts(
self,
id: Any,
+ since_id: Any = None,
+ until_id: Any = None,
max_results: int = None,
pagination_token: Any = None,
- listfields: List = None,
+ exclude: List = None,
+ start_time: str = None,
+ end_time: str = None,
+ tweet_fields: List = None,
expansions: List = None,
- userfields: List = None,
- ) -> GetOwnedListsResponse:
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
+ ) -> GetPostsResponse:
"""
- Get owned Lists
- Retrieves a list of Lists owned by a specific User by their ID.
+ Get Posts
+ Retrieves a list of posts authored by a specific User by their ID.
Args:
id: The ID of the User to lookup.
+ since_id: The minimum Post ID to be included in the result set. This parameter takes precedence over start_time if both are specified.
+ until_id: The maximum Post ID to be included in the result set. This parameter takes precedence over end_time if both are specified.
max_results: The maximum number of results.
- pagination_token: This parameter is used to get a specified 'page' of results.
- listfields: A comma separated list of List fields to display.
+ pagination_token: This parameter is used to get the next 'page' of results.
+ exclude: The set of entities to exclude (e.g. 'replies' or 'retweets').
+ 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.
+ 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.
+ tweet_fields: A comma separated list of Tweet fields to display.
expansions: A comma separated list of fields to expand.
- userfields: A comma separated list of User fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
Returns:
- GetOwnedListsResponse: Response data
+ GetPostsResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/owned_lists"
+ url = self.client.base_url + "/2/users/{id}/tweets"
url = url.replace("{id}", str(id))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
@@ -789,16 +776,32 @@ def get_owned_lists(
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 listfields is not None:
- params["list.fields"] = ",".join(str(item) for item in listfields)
+ 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 userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
+ 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 = {}
# Prepare request data
json_data = None
@@ -813,28 +816,33 @@ def get_owned_lists(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetOwnedListsResponse.model_validate(response_data)
+ return GetPostsResponse.model_validate(response_data)
- def get_by_usernames(
+ def get_followed_lists(
self,
- usernames: List,
- userfields: List = None,
+ id: Any,
+ max_results: int = None,
+ pagination_token: Any = None,
+ list_fields: List = None,
expansions: List = None,
- tweetfields: List = None,
- ) -> GetByUsernamesResponse:
+ user_fields: List = None,
+ ) -> GetFollowedListsResponse:
"""
- Get Users by usernames
- Retrieves details of multiple Users by their usernames.
+ Get followed Lists
+ Retrieves a list of Lists followed by a specific User by their ID.
Args:
- usernames: A list of usernames, comma-separated.
- userfields: A comma separated list of User fields to display.
+ id: The ID of the User to lookup.
+ max_results: The maximum number of results.
+ pagination_token: This parameter is used to get a specified 'page' of results.
+ list_fields: A comma separated list of List fields to display.
expansions: A comma separated list of fields to expand.
- tweetfields: A comma separated list of Tweet fields to display.
+ user_fields: A comma separated list of User fields to display.
Returns:
- GetByUsernamesResponse: Response data
+ GetFollowedListsResponse: Response data
"""
- url = self.client.base_url + "/2/users/by"
+ url = self.client.base_url + "/2/users/{id}/followed_lists"
+ url = url.replace("{id}", str(id))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
f"Bearer {self.client.bearer_token}"
@@ -849,14 +857,16 @@ def get_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 userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
+ 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 tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ if user_fields is not None:
+ params["user.fields"] = ",".join(str(item) for item in user_fields)
headers = {}
# Prepare request data
json_data = None
@@ -871,126 +881,82 @@ def get_by_usernames(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetByUsernamesResponse.model_validate(response_data)
+ return GetFollowedListsResponse.model_validate(response_data)
- def get_mentions(
- self,
- id: Any,
- since_id: Any = None,
- until_id: Any = None,
- max_results: int = None,
- pagination_token: Any = None,
- start_time: str = None,
- end_time: str = None,
- tweetfields: List = None,
- expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
- ) -> GetMentionsResponse:
+ def follow_list(
+ self, id: Any, body: Optional[FollowListRequest] = None
+ ) -> FollowListResponse:
"""
- Get mentions
- Retrieves a list of Posts that mention a specific User by their ID.
+ Follow List
+ Causes the authenticated user to follow a specific List by its ID.
Args:
- id: The ID of the User to lookup.
- since_id: The minimum Post ID to be included in the result set. This parameter takes precedence over start_time if both are specified.
- until_id: The maximum Post ID to be included in the result set. This parameter takes precedence over end_time if both are specified.
- max_results: The maximum number of results.
- pagination_token: This parameter is used to get the next 'page' of results.
- 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.
- 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.
- tweetfields: A comma separated list of Tweet fields to display.
- expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
- Returns:
- GetMentionsResponse: Response data
+ 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}/mentions"
+ url = self.client.base_url + "/2/users/{id}/followed_lists"
url = url.replace("{id}", str(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 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 tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
- if expansions is not None:
- params["expansions"] = ",".join(str(item) for item in expansions)
- if mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
headers = {}
+ headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
+ if body is not None:
+ json_data = (
+ body.model_dump(exclude_none=True)
+ if hasattr(body, "model_dump")
+ else body
+ )
# 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=json_data,
+ )
+ else:
+ response = self.client.session.post(
+ url,
+ params=params,
+ headers=headers,
+ json=json_data,
+ )
# Check for errors
response.raise_for_status()
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetMentionsResponse.model_validate(response_data)
+ return FollowListResponse.model_validate(response_data)
- def get_list_memberships(
+ def get_by_username(
self,
- id: Any,
- max_results: int = None,
- pagination_token: Any = None,
- listfields: List = None,
+ username: str,
+ user_fields: List = None,
expansions: List = None,
- userfields: List = None,
- ) -> GetListMembershipsResponse:
+ tweet_fields: List = None,
+ ) -> GetByUsernameResponse:
"""
- Get List memberships
- Retrieves a list of Lists that a specific User is a member of by their ID.
+ Get User by username
+ Retrieves details of a specific User by their username.
Args:
- id: The ID of the User to lookup.
- max_results: The maximum number of results.
- pagination_token: This parameter is used to get a specified 'page' of results.
- listfields: A comma separated list of List fields to display.
+ username: A username.
+ user_fields: A comma separated list of User fields to display.
expansions: A comma separated list of fields to expand.
- userfields: A comma separated list of User fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
Returns:
- GetListMembershipsResponse: Response data
+ GetByUsernameResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/list_memberships"
- url = url.replace("{id}", str(id))
+ url = self.client.base_url + "/2/users/by/username/{username}"
+ url = url.replace("{username}", str(username))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
f"Bearer {self.client.bearer_token}"
@@ -1005,16 +971,12 @@ def get_list_memberships(
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 listfields is not None:
- params["list.fields"] = ",".join(str(item) for item in listfields)
+ 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 userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
+ if tweet_fields is not None:
+ params["tweet.fields"] = ",".join(str(item) for item in tweet_fields)
headers = {}
# Prepare request data
json_data = None
@@ -1029,96 +991,125 @@ def get_list_memberships(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetListMembershipsResponse.model_validate(response_data)
+ return GetByUsernameResponse.model_validate(response_data)
- def get_blocking(
+ def get_mentions(
self,
id: Any,
+ since_id: Any = None,
+ until_id: Any = None,
max_results: int = None,
pagination_token: Any = None,
- userfields: List = None,
+ start_time: str = None,
+ end_time: str = None,
+ tweet_fields: List = None,
expansions: List = None,
- tweetfields: List = None,
- ) -> GetBlockingResponse:
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
+ ) -> GetMentionsResponse:
"""
- Get blocking
- Retrieves a list of Users blocked by the specified User ID.
+ Get mentions
+ Retrieves a list of Posts that mention 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.
+ since_id: The minimum Post ID to be included in the result set. This parameter takes precedence over start_time if both are specified.
+ until_id: The maximum Post ID to be included in the result set. This parameter takes precedence over end_time if both are specified.
max_results: The maximum number of results.
- pagination_token: This parameter is used to get a specified 'page' of results.
- userfields: A comma separated list of User fields to display.
+ pagination_token: This parameter is used to get the next 'page' of results.
+ 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.
+ 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.
+ tweet_fields: A comma separated list of Tweet fields to display.
expansions: A comma separated list of fields to expand.
- tweetfields: A comma separated list of Tweet fields to display.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
Returns:
- GetBlockingResponse: Response data
+ GetMentionsResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/blocking"
+ url = self.client.base_url + "/2/users/{id}/mentions"
url = url.replace("{id}", str(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 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 userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
+ 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 tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 = {}
# Prepare request data
json_data = None
# 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 GetBlockingResponse.model_validate(response_data)
+ return GetMentionsResponse.model_validate(response_data)
- def get_followed_lists(
+ def get_owned_lists(
self,
id: Any,
max_results: int = None,
pagination_token: Any = None,
- listfields: List = None,
+ list_fields: List = None,
expansions: List = None,
- userfields: List = None,
- ) -> GetFollowedListsResponse:
+ user_fields: List = None,
+ ) -> GetOwnedListsResponse:
"""
- Get followed Lists
- Retrieves a list of Lists followed by a specific User by their ID.
+ 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.
max_results: The maximum number of results.
pagination_token: This parameter is used to get a specified 'page' of results.
- listfields: A comma separated list of List fields to display.
+ list_fields: A comma separated list of List fields to display.
expansions: A comma separated list of fields to expand.
- userfields: A comma separated list of User fields to display.
+ user_fields: A comma separated list of User fields to display.
Returns:
- GetFollowedListsResponse: Response data
+ GetOwnedListsResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/followed_lists"
+ url = self.client.base_url + "/2/users/{id}/owned_lists"
url = url.replace("{id}", str(id))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
@@ -1138,12 +1129,12 @@ def get_followed_lists(
params["max_results"] = max_results
if pagination_token is not None:
params["pagination_token"] = pagination_token
- if listfields is not None:
- params["list.fields"] = ",".join(str(item) for item in listfields)
+ 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 userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
+ if user_fields is not None:
+ params["user.fields"] = ",".join(str(item) for item in user_fields)
headers = {}
# Prepare request data
json_data = None
@@ -1158,22 +1149,22 @@ def get_followed_lists(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetFollowedListsResponse.model_validate(response_data)
+ return GetOwnedListsResponse.model_validate(response_data)
- def follow_list(
- self, id: Any, body: Optional[FollowListRequest] = None
- ) -> FollowListResponse:
+ def repost_post(
+ self, id: Any, body: Optional[RepostPostRequest] = None
+ ) -> RepostPostResponse:
"""
- Follow List
- Causes the authenticated user to follow a specific List by its ID.
+ Repost Post
+ Causes the authenticated user to repost a specific Post by its ID.
Args:
- id: The ID of the authenticated source User that will follow the List.
+ id: The ID of the authenticated source User that is requesting to repost the Post.
body: Request body
Returns:
- FollowListResponse: Response data
+ RepostPostResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/followed_lists"
+ url = self.client.base_url + "/2/users/{id}/retweets"
url = url.replace("{id}", str(id))
# Ensure we have a valid access token
if self.client.oauth2_auth and self.client.token:
@@ -1211,22 +1202,22 @@ def follow_list(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return FollowListResponse.model_validate(response_data)
+ return RepostPostResponse.model_validate(response_data)
- def unrepost_post(self, id: Any, source_tweet_id: Any) -> UnrepostPostResponse:
+ def unfollow_list(self, id: Any, list_id: Any) -> UnfollowListResponse:
"""
- Unrepost Post
- Causes the authenticated user to unrepost a specific Post by its ID.
+ Unfollow List
+ Causes the authenticated user to unfollow a specific List by its ID.
Args:
- id: The ID of the authenticated source User that is requesting to repost the Post.
- source_tweet_id: The ID of the Post that the User is requesting to unretweet.
+ id: The ID of the authenticated source User that will unfollow the List.
+ list_id: The ID of the List to unfollow.
Returns:
- UnrepostPostResponse: Response data
+ UnfollowListResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/retweets/{source_tweet_id}"
+ url = self.client.base_url + "/2/users/{id}/followed_lists/{list_id}"
url = url.replace("{id}", str(id))
- url = url.replace("{source_tweet_id}", str(source_tweet_id))
+ url = url.replace("{list_id}", str(list_id))
# Ensure we have a valid access token
if self.client.oauth2_auth and self.client.token:
# Check if token needs refresh
@@ -1254,134 +1245,88 @@ def unrepost_post(self, id: Any, source_tweet_id: Any) -> UnrepostPostResponse:
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return UnrepostPostResponse.model_validate(response_data)
+ return UnfollowListResponse.model_validate(response_data)
- def get_reposts_of_me(
+ def get_by_ids(
self,
- max_results: int = None,
- pagination_token: Any = None,
- tweetfields: List = None,
+ ids: List,
+ user_fields: List = None,
expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
- ) -> GetRepostsOfMeResponse:
+ tweet_fields: List = None,
+ ) -> GetByIdsResponse:
"""
- Get Reposts of me
- Retrieves a list of Posts that repost content from the authenticated user.
+ Get Users by IDs
+ Retrieves details of multiple Users by their IDs.
Args:
- max_results: The maximum number of results.
- pagination_token: This parameter is used to get the next 'page' of results.
- tweetfields: A comma separated list of Tweet fields to display.
+ ids: A list of User IDs, comma-separated. You can specify up to 100 IDs.
+ user_fields: A comma separated list of User fields to display.
expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
Returns:
- GetRepostsOfMeResponse: Response data
+ GetByIdsResponse: Response data
"""
- url = self.client.base_url + "/2/users/reposts_of_me"
+ 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 max_results is not None:
- params["max_results"] = max_results
- if pagination_token is not None:
- params["pagination_token"] = pagination_token
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ 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 mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
+ if tweet_fields is not None:
+ params["tweet.fields"] = ",".join(str(item) for item in tweet_fields)
headers = {}
# Prepare request data
json_data = None
# 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 GetRepostsOfMeResponse.model_validate(response_data)
+ return GetByIdsResponse.model_validate(response_data)
- def get_bookmarks(
- self,
- id: Any,
- max_results: int = None,
- pagination_token: Any = None,
- tweetfields: List = None,
- expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
- ) -> GetBookmarksResponse:
+ def get_bookmarks_by_folder_id(
+ self, id: Any, folder_id: Any
+ ) -> GetBookmarksByFolderIdResponse:
"""
- 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.
- max_results: The maximum number of results.
- pagination_token: This parameter is used to get the next 'page' of results.
- tweetfields: A comma separated list of Tweet fields to display.
- expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: 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:
- GetBookmarksResponse: Response data
+ GetBookmarksByFolderIdResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/bookmarks"
+ url = self.client.base_url + "/2/users/{id}/bookmarks/folders/{folder_id}"
url = url.replace("{id}", str(id))
+ url = url.replace("{folder_id}", str(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 tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
- if expansions is not None:
- params["expansions"] = ",".join(str(item) for item in expansions)
- if mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
headers = {}
# Prepare request data
json_data = None
@@ -1403,22 +1348,19 @@ def get_bookmarks(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetBookmarksResponse.model_validate(response_data)
+ return GetBookmarksByFolderIdResponse.model_validate(response_data)
- def create_bookmark(
- self, id: Any, body: CreateBookmarkRequest
- ) -> CreateBookmarkResponse:
+ def unblock_dms(self, id: Any) -> UnblockDmsResponse:
"""
- Create Bookmark
- Adds a post to the authenticated user’s bookmarks.
+ Unblock DMs
+ Unblocks direct messages to or from a specific User by their ID for the authenticated user.
Args:
- id: The ID of the authenticated source User for whom to add bookmarks.
- body: Request body
- Returns:
- CreateBookmarkResponse: Response data
+ id: The ID of the target User that the authenticated user requesting to unblock dms for.
+ Returns:
+ UnblockDmsResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/bookmarks"
+ url = self.client.base_url + "/2/users/{id}/dm/unblock"
url = url.replace("{id}", str(id))
# Ensure we have a valid access token
if self.client.oauth2_auth and self.client.token:
@@ -1427,116 +1369,112 @@ def create_bookmark(
self.client.refresh_token()
params = {}
headers = {}
- headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
- if body is not None:
- json_data = (
- body.model_dump(exclude_none=True)
- if hasattr(body, "model_dump")
- else body
- )
# Make the request
if self.client.oauth2_session:
response = self.client.oauth2_session.post(
url,
params=params,
headers=headers,
- json=json_data,
)
else:
response = self.client.session.post(
url,
params=params,
headers=headers,
- json=json_data,
)
# Check for errors
response.raise_for_status()
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return CreateBookmarkResponse.model_validate(response_data)
+ return UnblockDmsResponse.model_validate(response_data)
- def get_by_ids(
+ def get_blocking(
self,
- ids: List,
- userfields: List = None,
+ id: Any,
+ max_results: int = None,
+ pagination_token: Any = None,
+ user_fields: List = None,
expansions: List = None,
- tweetfields: List = None,
- ) -> GetByIdsResponse:
+ tweet_fields: List = None,
+ ) -> GetBlockingResponse:
"""
- Get Users by IDs
- Retrieves details of multiple Users by their IDs.
+ Get blocking
+ Retrieves a list of Users blocked by the specified User ID.
Args:
- ids: A list of User IDs, comma-separated. You can specify up to 100 IDs.
- userfields: A comma separated list of User fields to display.
+ id: The ID of the authenticated source User for whom to return results.
+ max_results: The maximum number of results.
+ pagination_token: This parameter is used to get a specified 'page' of results.
+ user_fields: A comma separated list of User fields to display.
expansions: A comma separated list of fields to expand.
- tweetfields: A comma separated list of Tweet fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
Returns:
- GetByIdsResponse: Response data
+ GetBlockingResponse: 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}"
- )
+ url = self.client.base_url + "/2/users/{id}/blocking"
+ url = url.replace("{id}", str(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 ids is not None:
- params["ids"] = ",".join(str(item) for item in ids)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
+ 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 tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ if tweet_fields is not None:
+ params["tweet.fields"] = ",".join(str(item) for item in tweet_fields)
headers = {}
# Prepare request data
json_data = None
# 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 GetByIdsResponse.model_validate(response_data)
+ return GetBlockingResponse.model_validate(response_data)
- def get_by_id(
+ def get_by_usernames(
self,
- id: Any,
- userfields: List = None,
+ usernames: List,
+ user_fields: List = None,
expansions: List = None,
- tweetfields: List = None,
- ) -> GetByIdResponse:
+ tweet_fields: List = None,
+ ) -> GetByUsernamesResponse:
"""
- Get User by ID
- Retrieves details of a specific User by their ID.
+ Get Users by usernames
+ Retrieves details of multiple Users by their usernames.
Args:
- id: The ID of the User to lookup.
- userfields: A comma separated list of User fields to display.
+ usernames: A list of usernames, comma-separated.
+ user_fields: A comma separated list of User fields to display.
expansions: A comma separated list of fields to expand.
- tweetfields: A comma separated list of Tweet fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
Returns:
- GetByIdResponse: Response data
+ GetByUsernamesResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}"
- url = url.replace("{id}", str(id))
+ url = self.client.base_url + "/2/users/by"
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
f"Bearer {self.client.bearer_token}"
@@ -1551,12 +1489,14 @@ def get_by_id(
if self.client.is_token_expired():
self.client.refresh_token()
params = {}
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
+ 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 tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
+ if tweet_fields is not None:
+ params["tweet.fields"] = ",".join(str(item) for item in tweet_fields)
headers = {}
# Prepare request data
json_data = None
@@ -1571,46 +1511,45 @@ def get_by_id(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetByIdResponse.model_validate(response_data)
+ return GetByUsernamesResponse.model_validate(response_data)
- def get_bookmark_folders(
- self, id: Any, max_results: int = None, pagination_token: Any = None
- ) -> GetBookmarkFoldersResponse:
+ def unfollow_user(
+ self, source_user_id: Any, target_user_id: Any
+ ) -> UnfollowUserResponse:
"""
- Get Bookmark folders
- Retrieves a list of Bookmark folders created by the authenticated user.
+ Unfollow User
+ Causes the authenticated user to unfollow a specific user by their ID.
Args:
- id: The ID of the authenticated source User for whom to return results.
- max_results: The maximum number of results.
- pagination_token: This parameter is used to get the next 'page' of results.
+ source_user_id: The ID of the authenticated source User that is requesting to unfollow the target User.
+ target_user_id: The ID of the User that the source User is requesting to unfollow.
Returns:
- GetBookmarkFoldersResponse: Response data
+ UnfollowUserResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/bookmarks/folders"
- url = url.replace("{id}", str(id))
+ url = (
+ self.client.base_url
+ + "/2/users/{source_user_id}/following/{target_user_id}"
+ )
+ url = url.replace("{source_user_id}", str(source_user_id))
+ url = url.replace("{target_user_id}", str(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 = {}
- if max_results is not None:
- params["max_results"] = max_results
- if pagination_token is not None:
- params["pagination_token"] = pagination_token
headers = {}
# Prepare request data
json_data = None
# 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,
@@ -1620,19 +1559,19 @@ def get_bookmark_folders(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetBookmarkFoldersResponse.model_validate(response_data)
+ return UnfollowUserResponse.model_validate(response_data)
- def unblock_dms(self, id: Any) -> UnblockDmsResponse:
+ def block_dms(self, id: Any) -> BlockDmsResponse:
"""
- Unblock DMs
- Unblocks direct messages to or from a specific User by their ID for the authenticated user.
+ 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 unblock dms for.
+ id: The ID of the target User that the authenticated user requesting to block dms for.
Returns:
- UnblockDmsResponse: Response data
+ BlockDmsResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/dm/unblock"
+ url = self.client.base_url + "/2/users/{id}/dm/block"
url = url.replace("{id}", str(id))
# Ensure we have a valid access token
if self.client.oauth2_auth and self.client.token:
@@ -1661,145 +1600,145 @@ def unblock_dms(self, id: Any) -> UnblockDmsResponse:
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return UnblockDmsResponse.model_validate(response_data)
+ return BlockDmsResponse.model_validate(response_data)
- def get_pinned_lists(
+ def get_followers(
self,
id: Any,
- listfields: List = None,
+ max_results: int = None,
+ pagination_token: Any = None,
+ user_fields: List = None,
expansions: List = None,
- userfields: List = None,
- ) -> GetPinnedListsResponse:
+ tweet_fields: List = None,
+ ) -> GetFollowersResponse:
"""
- Get pinned Lists
- Retrieves a list of Lists pinned by the authenticated user.
+ Get followers
+ Retrieves a list of Users who follow a specific User by their ID.
Args:
- id: The ID of the authenticated source User for whom to return results.
- listfields: A comma separated list of List fields to display.
+ id: The ID of the User to lookup.
+ max_results: The maximum number of results.
+ pagination_token: This parameter is used to get a specified 'page' of results.
+ user_fields: A comma separated list of User fields to display.
expansions: A comma separated list of fields to expand.
- userfields: A comma separated list of User fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
Returns:
- GetPinnedListsResponse: Response data
+ GetFollowersResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/pinned_lists"
+ url = self.client.base_url + "/2/users/{id}/followers"
url = url.replace("{id}", str(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 listfields is not None:
- params["list.fields"] = ",".join(str(item) for item in listfields)
+ 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 userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
+ if tweet_fields is not None:
+ params["tweet.fields"] = ",".join(str(item) for item in tweet_fields)
headers = {}
# Prepare request data
json_data = None
# 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 GetPinnedListsResponse.model_validate(response_data)
+ return GetFollowersResponse.model_validate(response_data)
- def pin_list(self, id: Any, body: PinListRequest) -> PinListResponse:
+ def get_by_id(
+ self,
+ id: Any,
+ user_fields: List = None,
+ expansions: List = None,
+ tweet_fields: List = None,
+ ) -> GetByIdResponse:
"""
- Pin List
- Causes the authenticated user to pin a specific List by its ID.
+ Get User by ID
+ Retrieves details of a specific User by their ID.
Args:
- id: The ID of the authenticated source User that will pin the List.
- body: Request body
- Returns:
- PinListResponse: Response data
+ id: The ID of the User to lookup.
+ user_fields: A comma separated list of User fields to display.
+ expansions: A comma separated list of fields to expand.
+ tweet_fields: A comma separated list of Tweet fields to display.
+ Returns:
+ GetByIdResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/pinned_lists"
+ url = self.client.base_url + "/2/users/{id}"
url = url.replace("{id}", str(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)
headers = {}
- headers["Content-Type"] = "application/json"
# Prepare request data
json_data = None
- if body is not None:
- json_data = (
- body.model_dump(exclude_none=True)
- if hasattr(body, "model_dump")
- else body
- )
# Make the request
- if self.client.oauth2_session:
- response = self.client.oauth2_session.post(
- url,
- params=params,
- headers=headers,
- json=json_data,
- )
- else:
- response = self.client.session.post(
- url,
- params=params,
- headers=headers,
- json=json_data,
- )
+ 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 PinListResponse.model_validate(response_data)
+ return GetByIdResponse.model_validate(response_data)
- def get_liked_posts(
- self,
- id: Any,
- max_results: int = None,
- pagination_token: Any = None,
- tweetfields: List = None,
- expansions: List = None,
- mediafields: List = None,
- pollfields: List = None,
- userfields: List = None,
- placefields: List = None,
- ) -> GetLikedPostsResponse:
+ def get_bookmark_folders(
+ self, id: Any, max_results: int = None, pagination_token: Any = None
+ ) -> GetBookmarkFoldersResponse:
"""
- Get liked Posts
- Retrieves a list of Posts liked by a specific User by their ID.
+ Get Bookmark folders
+ Retrieves a list of Bookmark folders created by the authenticated user.
Args:
- id: The ID of the User to lookup.
+ id: The ID of the authenticated source User for whom to return results.
max_results: The maximum number of results.
pagination_token: This parameter is used to get the next 'page' of results.
- tweetfields: A comma separated list of Tweet fields to display.
- expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
Returns:
- GetLikedPostsResponse: Response data
+ GetBookmarkFoldersResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/liked_tweets"
+ url = self.client.base_url + "/2/users/{id}/bookmarks/folders"
url = url.replace("{id}", str(id))
# Ensure we have a valid access token
if self.client.oauth2_auth and self.client.token:
@@ -1811,18 +1750,6 @@ def get_liked_posts(
params["max_results"] = max_results
if pagination_token is not None:
params["pagination_token"] = pagination_token
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
- if expansions is not None:
- params["expansions"] = ",".join(str(item) for item in expansions)
- if mediafields is not None:
- params["media.fields"] = ",".join(str(item) for item in mediafields)
- if pollfields is not None:
- params["poll.fields"] = ",".join(str(item) for item in pollfields)
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if placefields is not None:
- params["place.fields"] = ",".join(str(item) for item in placefields)
headers = {}
# Prepare request data
json_data = None
@@ -1844,67 +1771,87 @@ def get_liked_posts(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return GetLikedPostsResponse.model_validate(response_data)
+ return GetBookmarkFoldersResponse.model_validate(response_data)
- def get_bookmarks_by_folder_id(
- self, id: Any, folder_id: Any
- ) -> GetBookmarksByFolderIdResponse:
+ def get_following(
+ self,
+ id: Any,
+ max_results: int = None,
+ pagination_token: Any = None,
+ user_fields: List = None,
+ expansions: List = None,
+ tweet_fields: List = None,
+ ) -> GetFollowingResponse:
"""
- Get Bookmarks by folder ID
- Retrieves Posts in a specific Bookmark folder by its ID for the authenticated user.
+ Get following
+ Retrieves a list of Users followed by a specific User by their ID.
Args:
- id: The ID of the authenticated source User for whom to return results.
- folder_id: The ID of the Bookmark Folder that the authenticated User is trying to fetch Posts for.
+ id: The ID of the User to lookup.
+ max_results: The maximum number of results.
+ pagination_token: This parameter is used to get a specified 'page' of results.
+ user_fields: A comma separated list of User fields to display.
+ expansions: A comma separated list of fields to expand.
+ tweet_fields: A comma separated list of Tweet fields to display.
Returns:
- GetBookmarksByFolderIdResponse: Response data
+ GetFollowingResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/bookmarks/folders/{folder_id}"
+ url = self.client.base_url + "/2/users/{id}/following"
url = url.replace("{id}", str(id))
- url = url.replace("{folder_id}", str(folder_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 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)
headers = {}
# Prepare request data
json_data = None
# 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 GetBookmarksByFolderIdResponse.model_validate(response_data)
+ return GetFollowingResponse.model_validate(response_data)
- def like_post(
- self, id: Any, body: Optional[LikePostRequest] = None
- ) -> LikePostResponse:
+ def follow_user(
+ self, id: Any, body: Optional[FollowUserRequest] = None
+ ) -> FollowUserResponse:
"""
- Like Post
- Causes the authenticated user to Like a specific Post by its ID.
+ 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 like the Post.
+ id: The ID of the authenticated source User that is requesting to follow the target User.
body: Request body
Returns:
- LikePostResponse: Response data
+ FollowUserResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/likes"
+ url = self.client.base_url + "/2/users/{id}/following"
url = url.replace("{id}", str(id))
# Ensure we have a valid access token
if self.client.oauth2_auth and self.client.token:
@@ -1942,40 +1889,93 @@ def like_post(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return LikePostResponse.model_validate(response_data)
+ return FollowUserResponse.model_validate(response_data)
- def unpin_list(self, id: Any, list_id: Any) -> UnpinListResponse:
+ def get_timeline(
+ self,
+ 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,
+ tweet_fields: List = None,
+ expansions: List = None,
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
+ ) -> GetTimelineResponse:
"""
- Unpin List
- Causes the authenticated user to unpin a specific List by its ID.
+ Get Timeline
+ Retrieves a reverse chronological list of Posts in the authenticated User’s Timeline.
Args:
- id: The ID of the authenticated source User for whom to return results.
- list_id: The ID of the List to unpin.
+ id: The ID of the authenticated source User to list Reverse Chronological Timeline Posts of.
+ since_id: The minimum Post ID to be included in the result set. This parameter takes precedence over start_time if both are specified.
+ until_id: The maximum Post ID to be included in the result set. This parameter takes precedence over end_time if both are specified.
+ max_results: The maximum number of results.
+ pagination_token: This parameter is used to get the next 'page' of results.
+ exclude: The set of entities to exclude (e.g. 'replies' or 'retweets').
+ 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.
+ 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.
+ tweet_fields: A comma separated list of Tweet fields to display.
+ expansions: A comma separated list of fields to expand.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
Returns:
- UnpinListResponse: Response data
+ GetTimelineResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/pinned_lists/{list_id}"
+ url = self.client.base_url + "/2/users/{id}/timelines/reverse_chronological"
url = url.replace("{id}", str(id))
- url = url.replace("{list_id}", str(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 = {}
+ 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)
headers = {}
# Prepare request data
json_data = None
# 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,
@@ -1985,97 +1985,62 @@ def unpin_list(self, id: Any, list_id: Any) -> UnpinListResponse:
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return UnpinListResponse.model_validate(response_data)
+ return GetTimelineResponse.model_validate(response_data)
- def get_by_username(
+ def search(
self,
- username: str,
- userfields: List = None,
+ query: Any,
+ max_results: int = None,
+ next_token: Any = None,
+ user_fields: List = None,
expansions: List = None,
- tweetfields: List = None,
- ) -> GetByUsernameResponse:
+ tweet_fields: List = None,
+ ) -> SearchResponse:
"""
- Get User by username
- Retrieves details of a specific User by their username.
+ Search Users
+ Retrieves a list of Users matching a search query.
Args:
- username: A username.
- userfields: A comma separated list of User fields to display.
+ query: TThe the query string by which to query for users.
+ max_results: The maximum number of results.
+ 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.
+ user_fields: A comma separated list of User fields to display.
expansions: A comma separated list of fields to expand.
- tweetfields: A comma separated list of Tweet fields to display.
+ tweet_fields: A comma separated list of Tweet fields to display.
Returns:
- GetByUsernameResponse: Response data
+ SearchResponse: Response data
"""
- url = self.client.base_url + "/2/users/by/username/{username}"
- url = url.replace("{username}", str(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}"
- )
+ 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 userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
+ 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 tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
- headers = {}
- # Prepare request data
- json_data = None
- # 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)
-
-
- def delete_bookmark(self, id: Any, tweet_id: Any) -> DeleteBookmarkResponse:
- """
- 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.
- tweet_id: The ID of the Post that the source User is removing from bookmarks.
- Returns:
- DeleteBookmarkResponse: Response data
- """
- url = self.client.base_url + "/2/users/{id}/bookmarks/{tweet_id}"
- url = url.replace("{id}", str(id))
- url = url.replace("{tweet_id}", str(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 = {}
+ if tweet_fields is not None:
+ params["tweet.fields"] = ",".join(str(item) for item in tweet_fields)
headers = {}
# Prepare request data
json_data = None
# 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,
@@ -2085,19 +2050,38 @@ def delete_bookmark(self, id: Any, tweet_id: Any) -> DeleteBookmarkResponse:
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return DeleteBookmarkResponse.model_validate(response_data)
+ return SearchResponse.model_validate(response_data)
- def block_dms(self, id: Any) -> BlockDmsResponse:
+ def get_bookmarks(
+ self,
+ id: Any,
+ max_results: int = None,
+ pagination_token: Any = None,
+ tweet_fields: List = None,
+ expansions: List = None,
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
+ ) -> GetBookmarksResponse:
"""
- Block DMs
- Blocks direct messages to or from a specific User by their ID for the authenticated user.
+ Get Bookmarks
+ Retrieves a list of Posts bookmarked by the authenticated user.
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 for whom to return results.
+ max_results: The maximum number of results.
+ pagination_token: This parameter is used to get the next 'page' of results.
+ tweet_fields: A comma separated list of Tweet fields to display.
+ expansions: A comma separated list of fields to expand.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
Returns:
- BlockDmsResponse: Response data
+ GetBookmarksResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/dm/block"
+ url = self.client.base_url + "/2/users/{id}/bookmarks"
url = url.replace("{id}", str(id))
# Ensure we have a valid access token
if self.client.oauth2_auth and self.client.token:
@@ -2105,18 +2089,34 @@ def block_dms(self, id: Any) -> BlockDmsResponse:
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 = {}
# Prepare request data
json_data = None
# 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,
@@ -2126,22 +2126,22 @@ def block_dms(self, id: Any) -> BlockDmsResponse:
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return BlockDmsResponse.model_validate(response_data)
+ return GetBookmarksResponse.model_validate(response_data)
- def repost_post(
- self, id: Any, body: Optional[RepostPostRequest] = None
- ) -> RepostPostResponse:
+ def create_bookmark(
+ self, id: Any, body: CreateBookmarkRequest
+ ) -> CreateBookmarkResponse:
"""
- Repost Post
- Causes the authenticated user to repost a specific Post by its ID.
+ Create Bookmark
+ Adds a post to the authenticated user’s bookmarks.
Args:
- id: The ID of the authenticated source User that is requesting to repost the Post.
+ id: The ID of the authenticated source User for whom to add bookmarks.
body: Request body
Returns:
- RepostPostResponse: Response data
+ CreateBookmarkResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/retweets"
+ url = self.client.base_url + "/2/users/{id}/bookmarks"
url = url.replace("{id}", str(id))
# Ensure we have a valid access token
if self.client.oauth2_auth and self.client.token:
@@ -2179,45 +2179,70 @@ def repost_post(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return RepostPostResponse.model_validate(response_data)
+ return CreateBookmarkResponse.model_validate(response_data)
- def unfollow_user(
- self, source_user_id: Any, target_user_id: Any
- ) -> UnfollowUserResponse:
+ def get_reposts_of_me(
+ self,
+ max_results: int = None,
+ pagination_token: Any = None,
+ tweet_fields: List = None,
+ expansions: List = None,
+ media_fields: List = None,
+ poll_fields: List = None,
+ user_fields: List = None,
+ place_fields: List = None,
+ ) -> GetRepostsOfMeResponse:
"""
- Unfollow User
- Causes the authenticated user to unfollow a specific user by their ID.
+ Get Reposts of me
+ Retrieves a list of Posts that repost content from the authenticated user.
Args:
- source_user_id: The ID of the authenticated source User that is requesting to unfollow the target User.
- target_user_id: The ID of the User that the source User is requesting to unfollow.
+ max_results: The maximum number of results.
+ pagination_token: This parameter is used to get the next 'page' of results.
+ tweet_fields: A comma separated list of Tweet fields to display.
+ expansions: A comma separated list of fields to expand.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
Returns:
- UnfollowUserResponse: Response data
+ GetRepostsOfMeResponse: Response data
"""
- url = (
- self.client.base_url
- + "/2/users/{source_user_id}/following/{target_user_id}"
- )
- url = url.replace("{source_user_id}", str(source_user_id))
- url = url.replace("{target_user_id}", str(target_user_id))
+ 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 = {}
# Prepare request data
json_data = None
# 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,
@@ -2227,69 +2252,47 @@ def unfollow_user(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return UnfollowUserResponse.model_validate(response_data)
+ return GetRepostsOfMeResponse.model_validate(response_data)
- def get_followers(
- self,
- id: Any,
- max_results: int = None,
- pagination_token: Any = None,
- userfields: List = None,
- expansions: List = None,
- tweetfields: List = None,
- ) -> GetFollowersResponse:
+ def unpin_list(self, id: Any, list_id: Any) -> UnpinListResponse:
"""
- Get followers
- Retrieves a list of Users who follow a specific User by their ID.
+ Unpin List
+ Causes the authenticated user to unpin a specific List by its ID.
Args:
- id: The ID of the User to lookup.
- max_results: The maximum number of results.
- pagination_token: This parameter is used to get a specified 'page' of results.
- userfields: A comma separated list of User fields to display.
- expansions: A comma separated list of fields to expand.
- tweetfields: A comma separated list of Tweet fields to display.
+ id: The ID of the authenticated source User for whom to return results.
+ list_id: The ID of the List to unpin.
Returns:
- GetFollowersResponse: Response data
+ UnpinListResponse: Response data
"""
- url = self.client.base_url + "/2/users/{id}/followers"
+ url = self.client.base_url + "/2/users/{id}/pinned_lists/{list_id}"
url = url.replace("{id}", str(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}"
- )
+ url = url.replace("{list_id}", str(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 = {}
- if max_results is not None:
- params["max_results"] = max_results
- if pagination_token is not None:
- params["pagination_token"] = pagination_token
- if userfields is not None:
- params["user.fields"] = ",".join(str(item) for item in userfields)
- if expansions is not None:
- params["expansions"] = ",".join(str(item) for item in expansions)
- if tweetfields is not None:
- params["tweet.fields"] = ",".join(str(item) for item in tweetfields)
headers = {}
# Prepare request data
json_data = None
# Make the request
- response = self.client.session.get(
- url,
- params=params,
- headers=headers,
- )
+ 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 GetFollowersResponse.model_validate(response_data)
+ return UnpinListResponse.model_validate(response_data)
diff --git a/xdk/python/xdk/users/models.py b/xdk/python/xdk/users/models.py
index ffa6c09a..e2e8b34c 100644
--- a/xdk/python/xdk/users/models.py
+++ b/xdk/python/xdk/users/models.py
@@ -16,20 +16,26 @@
from datetime import datetime
-# Models for get_me
+# Models for like_post
-class GetMeResponse(BaseModel):
- """Response model for get_me"""
+class LikePostRequest(BaseModel):
+ """Request model for like_post"""
+
+ model_config = ConfigDict(populate_by_name=True)
+
+
+class LikePostResponse(BaseModel):
+ """Response model for like_post"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for unfollow_list
+# Models for unlike_post
-class UnfollowListResponse(BaseModel):
- """Response model for unfollow_list"""
+class UnlikePostResponse(BaseModel):
+ """Response model for unlike_post"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
@@ -58,53 +64,35 @@ class MuteUserResponse(BaseModel):
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for unlike_post
-
-
-class UnlikePostResponse(BaseModel):
- """Response model for unlike_post"""
-
- model_config = ConfigDict(populate_by_name=True, extra="allow")
-
-
-# Models for get_posts
-
-
-class GetPostsResponse(BaseModel):
- """Response model for get_posts"""
-
- model_config = ConfigDict(populate_by_name=True, extra="allow")
-
-
-# Models for get_following
+# Models for get_pinned_lists
-class GetFollowingResponse(BaseModel):
- """Response model for get_following"""
+class GetPinnedListsResponse(BaseModel):
+ """Response model for get_pinned_lists"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for follow_user
+# Models for pin_list
-class FollowUserRequest(BaseModel):
- """Request model for follow_user"""
+class PinListRequest(BaseModel):
+ """Request model for pin_list"""
model_config = ConfigDict(populate_by_name=True)
-class FollowUserResponse(BaseModel):
- """Response model for follow_user"""
+class PinListResponse(BaseModel):
+ """Response model for pin_list"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_timeline
+# Models for unrepost_post
-class GetTimelineResponse(BaseModel):
- """Response model for get_timeline"""
+class UnrepostPostResponse(BaseModel):
+ """Response model for unrepost_post"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
@@ -118,56 +106,47 @@ class UnmuteUserResponse(BaseModel):
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for search
-
-
-class SearchResponse(BaseModel):
- """Response model for search"""
-
- model_config = ConfigDict(populate_by_name=True, extra="allow")
-
-
-# Models for get_owned_lists
+# Models for delete_bookmark
-class GetOwnedListsResponse(BaseModel):
- """Response model for get_owned_lists"""
+class DeleteBookmarkResponse(BaseModel):
+ """Response model for delete_bookmark"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_by_usernames
+# Models for get_list_memberships
-class GetByUsernamesResponse(BaseModel):
- """Response model for get_by_usernames"""
+class GetListMembershipsResponse(BaseModel):
+ """Response model for get_list_memberships"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_mentions
+# Models for get_me
-class GetMentionsResponse(BaseModel):
- """Response model for get_mentions"""
+class GetMeResponse(BaseModel):
+ """Response model for get_me"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_list_memberships
+# Models for get_liked_posts
-class GetListMembershipsResponse(BaseModel):
- """Response model for get_list_memberships"""
+class GetLikedPostsResponse(BaseModel):
+ """Response model for get_liked_posts"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_blocking
+# Models for get_posts
-class GetBlockingResponse(BaseModel):
- """Response model for get_blocking"""
+class GetPostsResponse(BaseModel):
+ """Response model for get_posts"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
@@ -196,71 +175,71 @@ class FollowListResponse(BaseModel):
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for unrepost_post
+# Models for get_by_username
-class UnrepostPostResponse(BaseModel):
- """Response model for unrepost_post"""
+class GetByUsernameResponse(BaseModel):
+ """Response model for get_by_username"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_reposts_of_me
+# Models for get_mentions
-class GetRepostsOfMeResponse(BaseModel):
- """Response model for get_reposts_of_me"""
+class GetMentionsResponse(BaseModel):
+ """Response model for get_mentions"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_bookmarks
+# Models for get_owned_lists
-class GetBookmarksResponse(BaseModel):
- """Response model for get_bookmarks"""
+class GetOwnedListsResponse(BaseModel):
+ """Response model for get_owned_lists"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for create_bookmark
+# Models for repost_post
-class CreateBookmarkRequest(BaseModel):
- """Request model for create_bookmark"""
+class RepostPostRequest(BaseModel):
+ """Request model for repost_post"""
model_config = ConfigDict(populate_by_name=True)
-class CreateBookmarkResponse(BaseModel):
- """Response model for create_bookmark"""
+class RepostPostResponse(BaseModel):
+ """Response model for repost_post"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_by_ids
+# Models for unfollow_list
-class GetByIdsResponse(BaseModel):
- """Response model for get_by_ids"""
+class UnfollowListResponse(BaseModel):
+ """Response model for unfollow_list"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_by_id
+# Models for get_by_ids
-class GetByIdResponse(BaseModel):
- """Response model for get_by_id"""
+class GetByIdsResponse(BaseModel):
+ """Response model for get_by_ids"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_bookmark_folders
+# Models for get_bookmarks_by_folder_id
-class GetBookmarkFoldersResponse(BaseModel):
- """Response model for get_bookmark_folders"""
+class GetBookmarksByFolderIdResponse(BaseModel):
+ """Response model for get_bookmarks_by_folder_id"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
@@ -274,127 +253,148 @@ class UnblockDmsResponse(BaseModel):
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_pinned_lists
+# Models for get_blocking
-class GetPinnedListsResponse(BaseModel):
- """Response model for get_pinned_lists"""
+class GetBlockingResponse(BaseModel):
+ """Response model for get_blocking"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for pin_list
+# Models for get_by_usernames
-class PinListRequest(BaseModel):
- """Request model for pin_list"""
+class GetByUsernamesResponse(BaseModel):
+ """Response model for get_by_usernames"""
- model_config = ConfigDict(populate_by_name=True)
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
-class PinListResponse(BaseModel):
- """Response model for pin_list"""
+# Models for unfollow_user
+
+
+class UnfollowUserResponse(BaseModel):
+ """Response model for unfollow_user"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_liked_posts
+# Models for block_dms
-class GetLikedPostsResponse(BaseModel):
- """Response model for get_liked_posts"""
+class BlockDmsResponse(BaseModel):
+ """Response model for block_dms"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_bookmarks_by_folder_id
+# Models for get_followers
-class GetBookmarksByFolderIdResponse(BaseModel):
- """Response model for get_bookmarks_by_folder_id"""
+class GetFollowersResponse(BaseModel):
+ """Response model for get_followers"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for like_post
+# Models for get_by_id
-class LikePostRequest(BaseModel):
- """Request model for like_post"""
+class GetByIdResponse(BaseModel):
+ """Response model for get_by_id"""
- model_config = ConfigDict(populate_by_name=True)
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
-class LikePostResponse(BaseModel):
- """Response model for like_post"""
+# Models for get_bookmark_folders
+
+
+class GetBookmarkFoldersResponse(BaseModel):
+ """Response model for get_bookmark_folders"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for unpin_list
+# Models for get_following
-class UnpinListResponse(BaseModel):
- """Response model for unpin_list"""
+class GetFollowingResponse(BaseModel):
+ """Response model for get_following"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_by_username
+# Models for follow_user
-class GetByUsernameResponse(BaseModel):
- """Response model for get_by_username"""
+class FollowUserRequest(BaseModel):
+ """Request model for follow_user"""
+
+ model_config = ConfigDict(populate_by_name=True)
+
+
+class FollowUserResponse(BaseModel):
+ """Response model for follow_user"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for delete_bookmark
+# Models for get_timeline
-class DeleteBookmarkResponse(BaseModel):
- """Response model for delete_bookmark"""
+class GetTimelineResponse(BaseModel):
+ """Response model for get_timeline"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for block_dms
+# Models for search
-class BlockDmsResponse(BaseModel):
- """Response model for block_dms"""
+class SearchResponse(BaseModel):
+ """Response model for search"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for repost_post
+# Models for get_bookmarks
-class RepostPostRequest(BaseModel):
- """Request model for repost_post"""
+class GetBookmarksResponse(BaseModel):
+ """Response model for get_bookmarks"""
+
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
+
+
+# Models for create_bookmark
+
+
+class CreateBookmarkRequest(BaseModel):
+ """Request model for create_bookmark"""
model_config = ConfigDict(populate_by_name=True)
-class RepostPostResponse(BaseModel):
- """Response model for repost_post"""
+class CreateBookmarkResponse(BaseModel):
+ """Response model for create_bookmark"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for unfollow_user
+# Models for get_reposts_of_me
-class UnfollowUserResponse(BaseModel):
- """Response model for unfollow_user"""
+class GetRepostsOfMeResponse(BaseModel):
+ """Response model for get_reposts_of_me"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for get_followers
+# Models for unpin_list
-class GetFollowersResponse(BaseModel):
- """Response model for get_followers"""
+class UnpinListResponse(BaseModel):
+ """Response model for unpin_list"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
diff --git a/xdk/python/xdk/webhooks/client.py b/xdk/python/xdk/webhooks/client.py
index 8cdfd866..5f3a0dd7 100644
--- a/xdk/python/xdk/webhooks/client.py
+++ b/xdk/python/xdk/webhooks/client.py
@@ -22,13 +22,13 @@
from ..client import Client
from .models import (
GetStreamLinksResponse,
- ValidateResponse,
- DeleteResponse,
+ CreateStreamLinkResponse,
+ DeleteStreamLinkResponse,
GetResponse,
CreateRequest,
CreateResponse,
- CreateStreamLinkResponse,
- DeleteStreamLinkResponse,
+ ValidateResponse,
+ DeleteResponse,
)
@@ -76,16 +76,31 @@ def get_stream_links(
return GetStreamLinksResponse.model_validate(response_data)
- def validate(self, webhook_id: Any) -> ValidateResponse:
+ def create_stream_link(
+ self,
+ webhook_id: Any,
+ tweet_fields: str = None,
+ expansions: str = None,
+ media_fields: str = None,
+ poll_fields: str = None,
+ user_fields: str = None,
+ place_fields: str = None,
+ ) -> CreateStreamLinkResponse:
"""
- Validate webhook
- Triggers a CRC check for a given webhook.
+ Create stream link
+ Creates a link to deliver FilteredStream events to the given webhook.
Args:
- webhook_id: The ID of the webhook to check.
+ webhook_id: The webhook ID to link to your FilteredStream ruleset.
+ tweet_fields: A comma separated list of Tweet fields to display.
+ expansions: A comma separated list of fields to expand.
+ media_fields: A comma separated list of Media fields to display.
+ poll_fields: A comma separated list of Poll fields to display.
+ user_fields: A comma separated list of User fields to display.
+ place_fields: A comma separated list of Place fields to display.
Returns:
- ValidateResponse: Response data
+ CreateStreamLinkResponse: Response data
"""
- url = self.client.base_url + "/2/webhooks/{webhook_id}"
+ url = self.client.base_url + "/2/tweets/search/webhooks/{webhook_id}"
url = url.replace("{webhook_id}", str(webhook_id))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
@@ -96,11 +111,23 @@ def validate(self, webhook_id: Any) -> ValidateResponse:
f"Bearer {self.client.access_token}"
)
params = {}
+ if tweet_fields is not None:
+ params["tweet.fields"] = tweet_fields
+ if expansions is not None:
+ params["expansions"] = expansions
+ if media_fields is not None:
+ params["media.fields"] = media_fields
+ if poll_fields is not None:
+ params["poll.fields"] = poll_fields
+ if user_fields is not None:
+ params["user.fields"] = user_fields
+ if place_fields is not None:
+ params["place.fields"] = place_fields
headers = {}
# Prepare request data
json_data = None
# Make the request
- response = self.client.session.put(
+ response = self.client.session.post(
url,
params=params,
headers=headers,
@@ -110,19 +137,19 @@ def validate(self, webhook_id: Any) -> ValidateResponse:
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return ValidateResponse.model_validate(response_data)
+ return CreateStreamLinkResponse.model_validate(response_data)
- def delete(self, webhook_id: Any) -> DeleteResponse:
+ def delete_stream_link(self, webhook_id: Any) -> DeleteStreamLinkResponse:
"""
- Delete webhook
- Deletes an existing webhook configuration.
+ Delete stream link
+ Deletes a link from FilteredStream events to the given webhook.
Args:
- webhook_id: The ID of the webhook to delete.
+ webhook_id: The webhook ID to link to your FilteredStream ruleset.
Returns:
- DeleteResponse: Response data
+ DeleteStreamLinkResponse: Response data
"""
- url = self.client.base_url + "/2/webhooks/{webhook_id}"
+ url = self.client.base_url + "/2/tweets/search/webhooks/{webhook_id}"
url = url.replace("{webhook_id}", str(webhook_id))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
@@ -147,15 +174,15 @@ def delete(self, webhook_id: Any) -> DeleteResponse:
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return DeleteResponse.model_validate(response_data)
+ return DeleteStreamLinkResponse.model_validate(response_data)
- def get(self, webhook_configfields: List = None) -> GetResponse:
+ def get(self, webhook_config_fields: List = None) -> GetResponse:
"""
Get webhook
Get a list of webhook configs associated with a client app.
Args:
- webhook_configfields: A comma separated list of WebhookConfig fields to display.
+ webhook_config_fields: A comma separated list of WebhookConfig fields to display.
Returns:
GetResponse: Response data
"""
@@ -169,9 +196,9 @@ def get(self, webhook_configfields: List = None) -> GetResponse:
f"Bearer {self.client.access_token}"
)
params = {}
- if webhook_configfields is not None:
+ if webhook_config_fields is not None:
params["webhook_config.fields"] = ",".join(
- str(item) for item in webhook_configfields
+ str(item) for item in webhook_config_fields
)
headers = {}
# Prepare request data
@@ -233,31 +260,16 @@ def create(self, body: Optional[CreateRequest] = None) -> CreateResponse:
return CreateResponse.model_validate(response_data)
- def create_stream_link(
- self,
- webhook_id: Any,
- tweetfields: str = None,
- expansions: str = None,
- mediafields: str = None,
- pollfields: str = None,
- userfields: str = None,
- placefields: str = None,
- ) -> CreateStreamLinkResponse:
+ def validate(self, webhook_id: Any) -> ValidateResponse:
"""
- Create stream link
- Creates a link to deliver FilteredStream events to the given webhook.
+ Validate webhook
+ Triggers a CRC check for a given webhook.
Args:
- webhook_id: The webhook ID to link to your FilteredStream ruleset.
- tweetfields: A comma separated list of Tweet fields to display.
- expansions: A comma separated list of fields to expand.
- mediafields: A comma separated list of Media fields to display.
- pollfields: A comma separated list of Poll fields to display.
- userfields: A comma separated list of User fields to display.
- placefields: A comma separated list of Place fields to display.
+ webhook_id: The ID of the webhook to check.
Returns:
- CreateStreamLinkResponse: Response data
+ ValidateResponse: Response data
"""
- url = self.client.base_url + "/2/tweets/search/webhooks/{webhook_id}"
+ url = self.client.base_url + "/2/webhooks/{webhook_id}"
url = url.replace("{webhook_id}", str(webhook_id))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
@@ -268,23 +280,11 @@ def create_stream_link(
f"Bearer {self.client.access_token}"
)
params = {}
- if tweetfields is not None:
- params["tweet.fields"] = tweetfields
- if expansions is not None:
- params["expansions"] = expansions
- if mediafields is not None:
- params["media.fields"] = mediafields
- if pollfields is not None:
- params["poll.fields"] = pollfields
- if userfields is not None:
- params["user.fields"] = userfields
- if placefields is not None:
- params["place.fields"] = placefields
headers = {}
# Prepare request data
json_data = None
# Make the request
- response = self.client.session.post(
+ response = self.client.session.put(
url,
params=params,
headers=headers,
@@ -294,19 +294,19 @@ def create_stream_link(
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return CreateStreamLinkResponse.model_validate(response_data)
+ return ValidateResponse.model_validate(response_data)
- def delete_stream_link(self, webhook_id: Any) -> DeleteStreamLinkResponse:
+ def delete(self, webhook_id: Any) -> DeleteResponse:
"""
- Delete stream link
- Deletes a link from FilteredStream events to the given webhook.
+ Delete webhook
+ Deletes an existing webhook configuration.
Args:
- webhook_id: The webhook ID to link to your FilteredStream ruleset.
+ webhook_id: The ID of the webhook to delete.
Returns:
- DeleteStreamLinkResponse: Response data
+ DeleteResponse: Response data
"""
- url = self.client.base_url + "/2/tweets/search/webhooks/{webhook_id}"
+ url = self.client.base_url + "/2/webhooks/{webhook_id}"
url = url.replace("{webhook_id}", str(webhook_id))
if self.client.bearer_token:
self.client.session.headers["Authorization"] = (
@@ -331,4 +331,4 @@ def delete_stream_link(self, webhook_id: Any) -> DeleteStreamLinkResponse:
# Parse the response data
response_data = response.json()
# Convert to Pydantic model if applicable
- return DeleteStreamLinkResponse.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 a14a49f5..49bbfdad 100644
--- a/xdk/python/xdk/webhooks/models.py
+++ b/xdk/python/xdk/webhooks/models.py
@@ -25,20 +25,20 @@ class GetStreamLinksResponse(BaseModel):
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for validate
+# Models for create_stream_link
-class ValidateResponse(BaseModel):
- """Response model for validate"""
+class CreateStreamLinkResponse(BaseModel):
+ """Response model for create_stream_link"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for delete
+# Models for delete_stream_link
-class DeleteResponse(BaseModel):
- """Response model for delete"""
+class DeleteStreamLinkResponse(BaseModel):
+ """Response model for delete_stream_link"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
@@ -67,19 +67,19 @@ class CreateResponse(BaseModel):
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for create_stream_link
+# Models for validate
-class CreateStreamLinkResponse(BaseModel):
- """Response model for create_stream_link"""
+class ValidateResponse(BaseModel):
+ """Response model for validate"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
-# Models for delete_stream_link
+# Models for delete
-class DeleteStreamLinkResponse(BaseModel):
- """Response model for delete_stream_link"""
+class DeleteResponse(BaseModel):
+ """Response model for delete"""
model_config = ConfigDict(populate_by_name=True, extra="allow")
diff --git a/xdk/typescript/.gitignore b/xdk/typescript/.gitignore
new file mode 100644
index 00000000..a2515ba2
--- /dev/null
+++ b/xdk/typescript/.gitignore
@@ -0,0 +1,17 @@
+xdk/typescript/.gitignore # AUTO-GENERATED FILE - DO NOT EDIT
+# This file was automatically generated by the XDK build tool.
+# Any manual changes will be overwritten on the next generation.
+# Documentation generation outputs
+# These are generated by the docs scripts and should not be committed
+
+# TypeDoc output directories
+docs/
+docs/html/
+docs/markdown/
+docs/api/
+
+# Mintlify processed documentation
+mintlify-docs/
+
+# Temporary files created during doc generation
+tsconfig.docs.json
diff --git a/xdk/typescript/dist/index.cjs b/xdk/typescript/dist/index.cjs
index f79765b2..53845ffa 100644
--- a/xdk/typescript/dist/index.cjs
+++ b/xdk/typescript/dist/index.cjs
@@ -6643,11 +6643,11 @@ var HttpClient = class {
};
var httpClient = new HttpClient();
-// src/news/client.ts
-var NewsClient = class {
+// src/activity/client.ts
+var ActivityClient = class {
client;
/**
- * Creates a new news client instance
+ * Creates a new activity client instance
*
* @param client - The main X API client instance
*/
@@ -6672,50 +6672,25 @@ var NewsClient = class {
return normalized;
}
/**
- * Get news stories by ID
- * Retrieves news story by its ID.
-
-
- * @param id The ID of the news story.
-
+ * Get X activity subscriptions
+ * Get a list of active subscriptions for XAA
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async get(id, options = {}) {
- const paramMappings = {
- "news.fields": "newsFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
- const {
- newsFields = [],
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/news/{id}";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ async getSubscriptions() {
+ let path = "/2/activity/subscriptions";
const params = new URLSearchParams();
- if (newsFields !== void 0 && newsFields.length > 0) {
- params.append("news.fields", newsFields.join(","));
- }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
BearerToken: []
- },
- {
- OAuth2UserToken: ["tweet.read", "users.read"]
- },
- {
- UserToken: []
}
- ],
- ...requestOptions
+ ]
+ // No optional parameters, using empty request options
};
return this.client.request(
"GET",
@@ -6723,140 +6698,80 @@ var NewsClient = class {
finalRequestOptions
);
}
-};
-
-// src/news/models.ts
-var models_exports = {};
-
-// src/users/client.ts
-var UsersClient = class {
- client;
- /**
- * Creates a new users client instance
- *
- * @param client - The main X API client instance
- */
- constructor(client) {
- this.client = client;
- }
- /**
- * Normalize options object to handle both camelCase and original API parameter names
- * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
- */
- _normalizeOptions(options, paramMappings) {
- if (!options || typeof options !== "object") {
- return options;
- }
- const normalized = { ...options };
- for (const [originalName, camelName] of Object.entries(paramMappings)) {
- if (originalName in normalized && !(camelName in normalized)) {
- normalized[camelName] = normalized[originalName];
- delete normalized[originalName];
- }
- }
- return normalized;
- }
/**
- * Unlike Post
- * Causes the authenticated user to Unlike a specific Post by its ID.
-
-
- * @param id The ID of the authenticated source User that is requesting to unlike the Post.
-
-
-
- * @param tweetId The ID of the Post that the User is requesting to unlike.
-
+ * Create X activity subscription
+ * Creates a subscription for an X activity event
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async unlikePost(id, tweetId) {
- let path = "/2/users/{id}/likes/{tweet_id}";
- path = path.replace("{id}", encodeURIComponent(String(id)));
- path = path.replace("{tweet_id}", encodeURIComponent(String(tweetId)));
+ async createSubscription(options = {}) {
+ const normalizedOptions = options || {};
+ const {
+ body,
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/activity/subscriptions";
const params = new URLSearchParams();
const finalRequestOptions = {
+ body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["like.write", "tweet.read", "users.read"]
- },
- {
- UserToken: []
+ BearerToken: []
}
- ]
- // No optional parameters, using empty request options
+ ],
+ ...requestOptions
};
return this.client.request(
- "DELETE",
+ "POST",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get owned Lists
- * Retrieves a list of Lists owned by a specific User by their ID.
-
-
- * @param id The ID of the User to lookup.
-
+ * Activity Stream
+ * Stream of X Activities
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getOwnedLists(id, options = {}) {
+ async stream(options = {}) {
const paramMappings = {
- max_results: "maxResults",
- pagination_token: "paginationToken",
- "list.fields": "listFields",
- "user.fields": "userFields"
+ backfill_minutes: "backfillMinutes",
+ start_time: "startTime",
+ end_time: "endTime"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- maxResults = void 0,
- paginationToken = void 0,
- listFields = [],
- expansions = [],
- userFields = [],
+ backfillMinutes = void 0,
+ startTime = void 0,
+ endTime = void 0,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/{id}/owned_lists";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/activity/stream";
const params = new URLSearchParams();
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
- }
- if (listFields !== void 0 && listFields.length > 0) {
- params.append("list.fields", listFields.join(","));
+ if (backfillMinutes !== void 0) {
+ params.append("backfill_minutes", String(backfillMinutes));
}
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
+ if (startTime !== void 0) {
+ params.append("start_time", String(startTime));
}
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
+ if (endTime !== void 0) {
+ params.append("end_time", String(endTime));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
BearerToken: []
- },
- {
- OAuth2UserToken: ["list.read", "tweet.read", "users.read"]
- },
- {
- UserToken: []
}
],
...requestOptions
@@ -6868,100 +6783,71 @@ var UsersClient = class {
);
}
/**
- * Get blocking
- * Retrieves a list of Users blocked by the specified User ID.
+ * Update X activity subscription
+ * Updates a subscription for an X activity event
- * @param id The ID of the authenticated source User for whom to return results.
+ * @param subscriptionId The ID of the subscription to update.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getBlocking(id, options = {}) {
- const paramMappings = {
- max_results: "maxResults",
- pagination_token: "paginationToken",
- "user.fields": "userFields",
- "tweet.fields": "tweetFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
+ async updateSubscription(subscriptionId, options = {}) {
+ const normalizedOptions = options || {};
const {
- maxResults = void 0,
- paginationToken = void 0,
- userFields = [],
- expansions = [],
- tweetFields = [],
+ body,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/{id}/blocking";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/activity/subscriptions/{subscription_id}";
+ path = path.replace(
+ "{subscription_id}",
+ encodeURIComponent(String(subscriptionId))
+ );
const params = new URLSearchParams();
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
- }
const finalRequestOptions = {
+ body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["block.read", "tweet.read", "users.read"]
- },
- {
- UserToken: []
+ BearerToken: []
}
],
...requestOptions
};
return this.client.request(
- "GET",
+ "PUT",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Delete Bookmark
- * Removes a Post from the authenticated user’s Bookmarks by its ID.
-
-
- * @param id The ID of the authenticated source User whose bookmark is to be removed.
-
+ * Deletes X activity subscription
+ * Deletes a subscription for an X activity event
- * @param tweetId The ID of the Post that the source User is removing from bookmarks.
+ * @param subscriptionId The ID of the subscription to delete.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async deleteBookmark(id, tweetId) {
- let path = "/2/users/{id}/bookmarks/{tweet_id}";
- path = path.replace("{id}", encodeURIComponent(String(id)));
- path = path.replace("{tweet_id}", encodeURIComponent(String(tweetId)));
+ async deleteSubscription(subscriptionId) {
+ let path = "/2/activity/subscriptions/{subscription_id}";
+ path = path.replace(
+ "{subscription_id}",
+ encodeURIComponent(String(subscriptionId))
+ );
const params = new URLSearchParams();
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["bookmark.write", "tweet.read", "users.read"]
+ BearerToken: []
}
]
// No optional parameters, using empty request options
@@ -6972,45 +6858,69 @@ var UsersClient = class {
finalRequestOptions
);
}
- /**
- * Get User by username
- * Retrieves details of a specific User by their username.
-
-
- * @param username A username.
+};
+
+// src/activity/models.ts
+var models_exports = {};
+
+// src/news/client.ts
+var NewsClient = class {
+ client;
+ /**
+ * Creates a new news client instance
+ *
+ * @param client - The main X API client instance
+ */
+ constructor(client) {
+ this.client = client;
+ }
+ /**
+ * Normalize options object to handle both camelCase and original API parameter names
+ * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
+ */
+ _normalizeOptions(options, paramMappings) {
+ if (!options || typeof options !== "object") {
+ return options;
+ }
+ const normalized = { ...options };
+ for (const [originalName, camelName] of Object.entries(paramMappings)) {
+ if (originalName in normalized && !(camelName in normalized)) {
+ normalized[camelName] = normalized[originalName];
+ delete normalized[originalName];
+ }
+ }
+ return normalized;
+ }
+ /**
+ * Get news stories by ID
+ * Retrieves news story by its ID.
+ * @param id The ID of the news story.
- * @returns {Promise} Promise resolving to the API response
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getByUsername(username, options = {}) {
+ async get(id, options = {}) {
const paramMappings = {
- "user.fields": "userFields",
- "tweet.fields": "tweetFields"
+ "news.fields": "newsFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- userFields = [],
- expansions = [],
- tweetFields = [],
+ newsFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/by/username/{username}";
- path = path.replace("{username}", encodeURIComponent(String(username)));
+ let path = "/2/news/{id}";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ if (newsFields !== void 0 && newsFields.length > 0) {
+ params.append("news.fields", newsFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
@@ -7034,133 +6944,47 @@ var UsersClient = class {
);
}
/**
- * Unpin List
- * Causes the authenticated user to unpin a specific List by its ID.
-
-
- * @param id The ID of the authenticated source User for whom to return results.
-
-
-
- * @param listId The ID of the List to unpin.
-
-
-
-
- * @returns {Promise} Promise resolving to the API response
- */
- // Overload 1: Default behavior (unwrapped response)
- async unpinList(id, listId) {
- let path = "/2/users/{id}/pinned_lists/{list_id}";
- path = path.replace("{id}", encodeURIComponent(String(id)));
- path = path.replace("{list_id}", encodeURIComponent(String(listId)));
- const params = new URLSearchParams();
- const finalRequestOptions = {
- // Pass security requirements for smart auth selection
- security: [
- {
- OAuth2UserToken: ["list.write", "tweet.read", "users.read"]
- },
- {
- UserToken: []
- }
- ]
- // No optional parameters, using empty request options
- };
- return this.client.request(
- "DELETE",
- path + (params.toString() ? `?${params.toString()}` : ""),
- finalRequestOptions
- );
- }
- /**
- * Get Posts
- * Retrieves a list of posts authored by a specific User by their ID.
+ * Search News
+ * Retrieves a list of News stories matching the specified search query.
- * @param id The ID of the User to lookup.
+ * @param query The search query.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getPosts(id, options = {}) {
+ async search(query, options = {}) {
const paramMappings = {
- since_id: "sinceId",
- until_id: "untilId",
max_results: "maxResults",
- pagination_token: "paginationToken",
- start_time: "startTime",
- end_time: "endTime",
- "tweet.fields": "tweetFields",
- "media.fields": "mediaFields",
- "poll.fields": "pollFields",
- "user.fields": "userFields",
- "place.fields": "placeFields"
+ max_age_hours: "maxAgeHours",
+ "news.fields": "newsFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- sinceId = void 0,
- untilId = void 0,
maxResults = void 0,
- paginationToken = void 0,
- exclude = [],
- startTime = void 0,
- endTime = void 0,
- tweetFields = [],
- expansions = [],
- mediaFields = [],
- pollFields = [],
- userFields = [],
- placeFields = [],
+ maxAgeHours = void 0,
+ newsFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/{id}/tweets";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/news/search";
const params = new URLSearchParams();
- if (sinceId !== void 0) {
- params.append("since_id", String(sinceId));
- }
- if (untilId !== void 0) {
- params.append("until_id", String(untilId));
+ if (query !== void 0) {
+ params.append("query", String(query));
}
if (maxResults !== void 0) {
params.append("max_results", String(maxResults));
}
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
- }
- if (exclude !== void 0 && exclude.length > 0) {
- params.append("exclude", exclude.join(","));
- }
- if (startTime !== void 0) {
- params.append("start_time", String(startTime));
- }
- if (endTime !== void 0) {
- params.append("end_time", String(endTime));
- }
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (mediaFields !== void 0 && mediaFields.length > 0) {
- params.append("media.fields", mediaFields.join(","));
- }
- if (pollFields !== void 0 && pollFields.length > 0) {
- params.append("poll.fields", pollFields.join(","));
+ if (maxAgeHours !== void 0) {
+ params.append("max_age_hours", String(maxAgeHours));
}
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (placeFields !== void 0 && placeFields.length > 0) {
- params.append("place.fields", placeFields.join(","));
+ if (newsFields !== void 0 && newsFields.length > 0) {
+ params.append("news.fields", newsFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
@@ -7170,9 +6994,6 @@ var UsersClient = class {
},
{
OAuth2UserToken: ["tweet.read", "users.read"]
- },
- {
- UserToken: []
}
],
...requestOptions
@@ -7183,143 +7004,153 @@ var UsersClient = class {
finalRequestOptions
);
}
+};
+
+// src/news/models.ts
+var models_exports2 = {};
+
+// src/connections/client.ts
+var ConnectionsClient = class {
+ client;
/**
- * Get Bookmarks
- * Retrieves a list of Posts bookmarked by the authenticated user.
-
-
- * @param id The ID of the authenticated source User for whom to return results.
-
+ * Creates a new connections client instance
+ *
+ * @param client - The main X API client instance
+ */
+ constructor(client) {
+ this.client = client;
+ }
+ /**
+ * Normalize options object to handle both camelCase and original API parameter names
+ * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
+ */
+ _normalizeOptions(options, paramMappings) {
+ if (!options || typeof options !== "object") {
+ return options;
+ }
+ const normalized = { ...options };
+ for (const [originalName, camelName] of Object.entries(paramMappings)) {
+ if (originalName in normalized && !(camelName in normalized)) {
+ normalized[camelName] = normalized[originalName];
+ delete normalized[originalName];
+ }
+ }
+ return normalized;
+ }
+ /**
+ * Terminate all connections
+ * Terminates all active streaming connections for the authenticated application.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getBookmarks(id, options = {}) {
- const paramMappings = {
- max_results: "maxResults",
- pagination_token: "paginationToken",
- "tweet.fields": "tweetFields",
- "media.fields": "mediaFields",
- "poll.fields": "pollFields",
- "user.fields": "userFields",
- "place.fields": "placeFields"
+ async deleteAll() {
+ let path = "/2/connections/all";
+ const params = new URLSearchParams();
+ const finalRequestOptions = {
+ // Pass security requirements for smart auth selection
+ security: [
+ {
+ BearerToken: []
+ }
+ ]
+ // No optional parameters, using empty request options
};
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
+ return this.client.request(
+ "DELETE",
+ path + (params.toString() ? `?${params.toString()}` : ""),
+ finalRequestOptions
);
- const {
- maxResults = void 0,
- paginationToken = void 0,
- tweetFields = [],
- expansions = [],
- mediaFields = [],
- pollFields = [],
- userFields = [],
- placeFields = [],
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/users/{id}/bookmarks";
- path = path.replace("{id}", encodeURIComponent(String(id)));
- const params = new URLSearchParams();
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
- }
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (mediaFields !== void 0 && mediaFields.length > 0) {
- params.append("media.fields", mediaFields.join(","));
- }
- if (pollFields !== void 0 && pollFields.length > 0) {
- params.append("poll.fields", pollFields.join(","));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
+ }
+};
+
+// src/connections/models.ts
+var models_exports3 = {};
+
+// src/account_activity/client.ts
+var AccountActivityClient = class {
+ client;
+ /**
+ * Creates a new account activity client instance
+ *
+ * @param client - The main X API client instance
+ */
+ constructor(client) {
+ this.client = client;
+ }
+ /**
+ * Normalize options object to handle both camelCase and original API parameter names
+ * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
+ */
+ _normalizeOptions(options, paramMappings) {
+ if (!options || typeof options !== "object") {
+ return options;
}
- if (placeFields !== void 0 && placeFields.length > 0) {
- params.append("place.fields", placeFields.join(","));
+ const normalized = { ...options };
+ for (const [originalName, camelName] of Object.entries(paramMappings)) {
+ if (originalName in normalized && !(camelName in normalized)) {
+ normalized[camelName] = normalized[originalName];
+ delete normalized[originalName];
+ }
}
- const finalRequestOptions = {
- // Pass security requirements for smart auth selection
- security: [
- {
- OAuth2UserToken: ["bookmark.read", "tweet.read", "users.read"]
- }
- ],
- ...requestOptions
- };
- return this.client.request(
- "GET",
- path + (params.toString() ? `?${params.toString()}` : ""),
- finalRequestOptions
- );
+ return normalized;
}
/**
- * Create Bookmark
- * Adds a post to the authenticated user’s bookmarks.
-
+ * Get subscriptions
+ * Retrieves a list of all active subscriptions for a given webhook.
- * @param id The ID of the authenticated source User for whom to add bookmarks.
+ * @param webhookId The webhook ID to pull subscriptions for.
- * @param body Request body
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async createBookmark(id, body) {
- let path = "/2/users/{id}/bookmarks";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ async getSubscriptions(webhookId) {
+ let path = "/2/account_activity/webhooks/{webhook_id}/subscriptions/all/list";
+ path = path.replace("{webhook_id}", encodeURIComponent(String(webhookId)));
const params = new URLSearchParams();
const finalRequestOptions = {
- body: JSON.stringify(body || {}),
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["bookmark.write", "tweet.read", "users.read"]
+ BearerToken: []
}
]
// No optional parameters, using empty request options
};
return this.client.request(
- "POST",
+ "GET",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Block DMs
- * Blocks direct messages to or from a specific User by their ID for the authenticated user.
+ * Validate subscription
+ * Checks a user’s Account Activity subscription for a given webhook.
- * @param id The ID of the target User that the authenticated user requesting to block dms for.
+ * @param webhookId The webhook ID to check subscription against.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async blockDms(id) {
- let path = "/2/users/{id}/dm/block";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ async validateSubscription(webhookId) {
+ let path = "/2/account_activity/webhooks/{webhook_id}/subscriptions/all";
+ path = path.replace("{webhook_id}", encodeURIComponent(String(webhookId)));
const params = new URLSearchParams();
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["dm.write", "tweet.read", "users.read"]
+ OAuth2UserToken: ["dm.read", "dm.write", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -7328,112 +7159,72 @@ var UsersClient = class {
// No optional parameters, using empty request options
};
return this.client.request(
- "POST",
+ "GET",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Unfollow List
- * Causes the authenticated user to unfollow a specific List by its ID.
-
-
- * @param id The ID of the authenticated source User that will unfollow the List.
-
+ * Create subscription
+ * Creates an Account Activity subscription for the user and the given webhook.
- * @param listId The ID of the List to unfollow.
+ * @param webhookId The webhook ID to check subscription against.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async unfollowList(id, listId) {
- let path = "/2/users/{id}/followed_lists/{list_id}";
- path = path.replace("{id}", encodeURIComponent(String(id)));
- path = path.replace("{list_id}", encodeURIComponent(String(listId)));
+ async createSubscription(webhookId, options = {}) {
+ const normalizedOptions = options || {};
+ const {
+ body,
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/account_activity/webhooks/{webhook_id}/subscriptions/all";
+ path = path.replace("{webhook_id}", encodeURIComponent(String(webhookId)));
const params = new URLSearchParams();
const finalRequestOptions = {
+ body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["list.write", "tweet.read", "users.read"]
+ OAuth2UserToken: ["dm.read", "dm.write", "tweet.read", "users.read"]
},
{
UserToken: []
}
- ]
- // No optional parameters, using empty request options
+ ],
+ ...requestOptions
};
return this.client.request(
- "DELETE",
+ "POST",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get muting
- * Retrieves a list of Users muted by the authenticated user.
-
-
- * @param id The ID of the authenticated source User for whom to return results.
-
+ * Get subscription count
+ * Retrieves a count of currently active Account Activity subscriptions.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getMuting(id, options = {}) {
- const paramMappings = {
- max_results: "maxResults",
- pagination_token: "paginationToken",
- "user.fields": "userFields",
- "tweet.fields": "tweetFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
- const {
- maxResults = void 0,
- paginationToken = void 0,
- userFields = [],
- expansions = [],
- tweetFields = [],
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/users/{id}/muting";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ async getSubscriptionCount() {
+ let path = "/2/account_activity/subscriptions/count";
const params = new URLSearchParams();
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
- }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["mute.read", "tweet.read", "users.read"]
- },
- {
- UserToken: []
+ BearerToken: []
}
- ],
- ...requestOptions
+ ]
+ // No optional parameters, using empty request options
};
return this.client.request(
"GET",
@@ -7442,150 +7233,174 @@ var UsersClient = class {
);
}
/**
- * Mute User
- * Causes the authenticated user to mute a specific User by their ID.
+ * Delete subscription
+ * Deletes an Account Activity subscription for the given webhook and user ID.
- * @param id The ID of the authenticated source User that is requesting to mute the target User.
+ * @param webhookId The webhook ID to check subscription against.
+ * @param userId User ID to unsubscribe from.
- * @returns {Promise} Promise resolving to the API response
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async muteUser(id, options = {}) {
- const normalizedOptions = options || {};
- const {
- body,
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/users/{id}/muting";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ async deleteSubscription(webhookId, userId) {
+ let path = "/2/account_activity/webhooks/{webhook_id}/subscriptions/{user_id}/all";
+ path = path.replace("{webhook_id}", encodeURIComponent(String(webhookId)));
+ path = path.replace("{user_id}", encodeURIComponent(String(userId)));
const params = new URLSearchParams();
const finalRequestOptions = {
- body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["mute.write", "tweet.read", "users.read"]
- },
- {
- UserToken: []
+ BearerToken: []
}
- ],
- ...requestOptions
+ ]
+ // No optional parameters, using empty request options
};
return this.client.request(
- "POST",
+ "DELETE",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get User by ID
- * Retrieves details of a specific User by their ID.
+ * 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.
- * @param id The ID of the User to lookup.
+ * @param webhookId The unique identifier for the webhook configuration.
- * @returns {Promise} Promise resolving to the API response
+ * @param fromDate The oldest (starting) UTC timestamp (inclusive) from which events will be provided, in `yyyymmddhhmm` format.
+
+
+
+ * @param toDate The latest (ending) UTC timestamp (exclusive) up to which events will be provided, in `yyyymmddhhmm` format.
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getById(id, options = {}) {
- const paramMappings = {
- "user.fields": "userFields",
- "tweet.fields": "tweetFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
- const {
- userFields = [],
- expansions = [],
- tweetFields = [],
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/users/{id}";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ async createReplayJob(webhookId, fromDate, toDate) {
+ let path = "/2/account_activity/replay/webhooks/{webhook_id}/subscriptions/all";
+ path = path.replace("{webhook_id}", encodeURIComponent(String(webhookId)));
const params = new URLSearchParams();
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
+ if (fromDate !== void 0) {
+ params.append("from_date", String(fromDate));
}
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ if (toDate !== void 0) {
+ params.append("to_date", String(toDate));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
BearerToken: []
- },
- {
- OAuth2UserToken: ["tweet.read", "users.read"]
- },
- {
- UserToken: []
}
- ],
- ...requestOptions
+ ]
+ // No optional parameters, using empty request options
};
return this.client.request(
- "GET",
+ "POST",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
+};
+
+// src/account_activity/models.ts
+var models_exports4 = {};
+
+// src/spaces/client.ts
+var SpacesClient = class {
+ client;
+ /**
+ * Creates a new spaces client instance
+ *
+ * @param client - The main X API client instance
+ */
+ constructor(client) {
+ this.client = client;
+ }
/**
- * Get my User
- * Retrieves details of the authenticated user.
+ * Normalize options object to handle both camelCase and original API parameter names
+ * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
+ */
+ _normalizeOptions(options, paramMappings) {
+ if (!options || typeof options !== "object") {
+ return options;
+ }
+ const normalized = { ...options };
+ for (const [originalName, camelName] of Object.entries(paramMappings)) {
+ if (originalName in normalized && !(camelName in normalized)) {
+ normalized[camelName] = normalized[originalName];
+ delete normalized[originalName];
+ }
+ }
+ return normalized;
+ }
+ /**
+ * Get space by ID
+ * Retrieves details of a specific space by its ID.
+ * @param id The ID of the Space to be retrieved.
- * @returns {Promise} Promise resolving to the API response
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getMe(options = {}) {
+ async getById(id, options = {}) {
const paramMappings = {
+ "space.fields": "spaceFields",
"user.fields": "userFields",
- "tweet.fields": "tweetFields"
+ "topic.fields": "topicFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- userFields = [],
+ spaceFields = [],
expansions = [],
- tweetFields = [],
+ userFields = [],
+ topicFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/me";
+ let path = "/2/spaces/{id}";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
+ if (spaceFields !== void 0 && spaceFields.length > 0) {
+ params.append("space.fields", spaceFields.join(","));
}
if (expansions !== void 0 && expansions.length > 0) {
params.append("expansions", expansions.join(","));
}
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (topicFields !== void 0 && topicFields.length > 0) {
+ params.append("topic.fields", topicFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["tweet.read", "users.read"]
+ BearerToken: []
},
{
- UserToken: []
+ OAuth2UserToken: ["space.read", "tweet.read", "users.read"]
}
],
...requestOptions
@@ -7597,111 +7412,22 @@ var UsersClient = class {
);
}
/**
- * Unrepost Post
- * Causes the authenticated user to unrepost a specific Post by its ID.
-
-
- * @param id The ID of the authenticated source User that is requesting to repost the Post.
-
-
-
- * @param sourceTweetId The ID of the Post that the User is requesting to unretweet.
-
-
-
-
- * @returns {Promise} Promise resolving to the API response
- */
- // Overload 1: Default behavior (unwrapped response)
- async unrepostPost(id, sourceTweetId) {
- let path = "/2/users/{id}/retweets/{source_tweet_id}";
- path = path.replace("{id}", encodeURIComponent(String(id)));
- path = path.replace(
- "{source_tweet_id}",
- encodeURIComponent(String(sourceTweetId))
- );
- const params = new URLSearchParams();
- const finalRequestOptions = {
- // Pass security requirements for smart auth selection
- security: [
- {
- OAuth2UserToken: ["tweet.read", "tweet.write", "users.read"]
- },
- {
- UserToken: []
- }
- ]
- // No optional parameters, using empty request options
- };
- return this.client.request(
- "DELETE",
- path + (params.toString() ? `?${params.toString()}` : ""),
- finalRequestOptions
- );
- }
- /**
- * Unmute User
- * Causes the authenticated user to unmute a specific user by their ID.
-
-
- * @param sourceUserId The ID of the authenticated source User that is requesting to unmute the target User.
-
-
-
- * @param targetUserId The ID of the User that the source User is requesting to unmute.
-
-
-
-
- * @returns {Promise} Promise resolving to the API response
- */
- // Overload 1: Default behavior (unwrapped response)
- async unmuteUser(sourceUserId, targetUserId) {
- let path = "/2/users/{source_user_id}/muting/{target_user_id}";
- path = path.replace(
- "{source_user_id}",
- encodeURIComponent(String(sourceUserId))
- );
- path = path.replace(
- "{target_user_id}",
- encodeURIComponent(String(targetUserId))
- );
- const params = new URLSearchParams();
- const finalRequestOptions = {
- // Pass security requirements for smart auth selection
- security: [
- {
- OAuth2UserToken: ["mute.write", "tweet.read", "users.read"]
- },
- {
- UserToken: []
- }
- ]
- // No optional parameters, using empty request options
- };
- return this.client.request(
- "DELETE",
- path + (params.toString() ? `?${params.toString()}` : ""),
- finalRequestOptions
- );
- }
- /**
- * Search Users
- * Retrieves a list of Users matching a search query.
+ * Get Space ticket buyers
+ * Retrieves a list of Users who purchased tickets to a specific Space by its ID.
+ * @param id The ID of the Space to be retrieved.
- * @param query TThe the query string by which to query for users.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async search(query, options = {}) {
+ async getBuyers(id, options = {}) {
const paramMappings = {
+ pagination_token: "paginationToken",
max_results: "maxResults",
- next_token: "nextToken",
"user.fields": "userFields",
"tweet.fields": "tweetFields"
};
@@ -7710,24 +7436,22 @@ var UsersClient = class {
paramMappings
);
const {
+ paginationToken = void 0,
maxResults = void 0,
- nextToken = void 0,
userFields = [],
expansions = [],
tweetFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/search";
+ let path = "/2/spaces/{id}/buyers";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (query !== void 0) {
- params.append("query", String(query));
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
}
if (maxResults !== void 0) {
params.append("max_results", String(maxResults));
}
- if (nextToken !== void 0) {
- params.append("next_token", String(nextToken));
- }
if (userFields !== void 0 && userFields.length > 0) {
params.append("user.fields", userFields.join(","));
}
@@ -7741,10 +7465,7 @@ var UsersClient = class {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["tweet.read", "users.read"]
- },
- {
- UserToken: []
+ OAuth2UserToken: ["space.read", "tweet.read", "users.read"]
}
],
...requestOptions
@@ -7756,53 +7477,73 @@ var UsersClient = class {
);
}
/**
- * Get pinned Lists
- * Retrieves a list of Lists pinned by the authenticated user.
+ * Get Space Posts
+ * Retrieves a list of Posts shared in a specific Space by its ID.
- * @param id The ID of the authenticated source User for whom to return results.
+ * @param id The ID of the Space to be retrieved.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getPinnedLists(id, options = {}) {
+ async getPosts(id, options = {}) {
const paramMappings = {
- "list.fields": "listFields",
- "user.fields": "userFields"
+ max_results: "maxResults",
+ "tweet.fields": "tweetFields",
+ "media.fields": "mediaFields",
+ "poll.fields": "pollFields",
+ "user.fields": "userFields",
+ "place.fields": "placeFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- listFields = [],
+ maxResults = void 0,
+ tweetFields = [],
expansions = [],
+ mediaFields = [],
+ pollFields = [],
userFields = [],
+ placeFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/{id}/pinned_lists";
+ let path = "/2/spaces/{id}/tweets";
path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (listFields !== void 0 && listFields.length > 0) {
- params.append("list.fields", listFields.join(","));
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
}
if (expansions !== void 0 && expansions.length > 0) {
params.append("expansions", expansions.join(","));
}
+ if (mediaFields !== void 0 && mediaFields.length > 0) {
+ params.append("media.fields", mediaFields.join(","));
+ }
+ if (pollFields !== void 0 && pollFields.length > 0) {
+ params.append("poll.fields", pollFields.join(","));
+ }
if (userFields !== void 0 && userFields.length > 0) {
params.append("user.fields", userFields.join(","));
}
+ if (placeFields !== void 0 && placeFields.length > 0) {
+ params.append("place.fields", placeFields.join(","));
+ }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["list.read", "tweet.read", "users.read"]
+ BearerToken: []
},
{
- UserToken: []
+ OAuth2UserToken: ["space.read", "tweet.read", "users.read"]
}
],
...requestOptions
@@ -7814,86 +7555,107 @@ var UsersClient = class {
);
}
/**
- * Pin List
- * Causes the authenticated user to pin a specific List by its ID.
-
+ * Get Spaces by creator IDs
+ * Retrieves details of Spaces created by specified User IDs.
- * @param id The ID of the authenticated source User that will pin the List.
+ * @param userIds The IDs of Users to search through.
- * @param body Request body
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async pinList(id, body) {
- let path = "/2/users/{id}/pinned_lists";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ async getByCreatorIds(userIds, options = {}) {
+ const paramMappings = {
+ "space.fields": "spaceFields",
+ "user.fields": "userFields",
+ "topic.fields": "topicFields"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
+ const {
+ spaceFields = [],
+ expansions = [],
+ userFields = [],
+ topicFields = [],
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/spaces/by/creator_ids";
const params = new URLSearchParams();
+ if (userIds !== void 0 && userIds.length > 0) {
+ params.append("user_ids", userIds.join(","));
+ }
+ if (spaceFields !== void 0 && spaceFields.length > 0) {
+ params.append("space.fields", spaceFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (topicFields !== void 0 && topicFields.length > 0) {
+ params.append("topic.fields", topicFields.join(","));
+ }
const finalRequestOptions = {
- body: JSON.stringify(body || {}),
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["list.write", "tweet.read", "users.read"]
+ BearerToken: []
},
{
- UserToken: []
+ OAuth2UserToken: ["space.read", "tweet.read", "users.read"]
}
- ]
- // No optional parameters, using empty request options
+ ],
+ ...requestOptions
};
return this.client.request(
- "POST",
+ "GET",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get followed Lists
- * Retrieves a list of Lists followed by a specific User by their ID.
+ * Get Spaces by IDs
+ * Retrieves details of multiple Spaces by their IDs.
- * @param id The ID of the User to lookup.
+ * @param ids The list of Space IDs to return.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getFollowedLists(id, options = {}) {
+ async getByIds(ids, options = {}) {
const paramMappings = {
- max_results: "maxResults",
- pagination_token: "paginationToken",
- "list.fields": "listFields",
- "user.fields": "userFields"
+ "space.fields": "spaceFields",
+ "user.fields": "userFields",
+ "topic.fields": "topicFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- maxResults = void 0,
- paginationToken = void 0,
- listFields = [],
+ spaceFields = [],
expansions = [],
userFields = [],
+ topicFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/{id}/followed_lists";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/spaces";
const params = new URLSearchParams();
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
+ if (ids !== void 0 && ids.length > 0) {
+ params.append("ids", ids.join(","));
}
- if (listFields !== void 0 && listFields.length > 0) {
- params.append("list.fields", listFields.join(","));
+ if (spaceFields !== void 0 && spaceFields.length > 0) {
+ params.append("space.fields", spaceFields.join(","));
}
if (expansions !== void 0 && expansions.length > 0) {
params.append("expansions", expansions.join(","));
@@ -7901,6 +7663,9 @@ var UsersClient = class {
if (userFields !== void 0 && userFields.length > 0) {
params.append("user.fields", userFields.join(","));
}
+ if (topicFields !== void 0 && topicFields.length > 0) {
+ params.append("topic.fields", topicFields.join(","));
+ }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
@@ -7908,10 +7673,7 @@ var UsersClient = class {
BearerToken: []
},
{
- OAuth2UserToken: ["list.read", "tweet.read", "users.read"]
- },
- {
- UserToken: []
+ OAuth2UserToken: ["space.read", "tweet.read", "users.read"]
}
],
...requestOptions
@@ -7923,74 +7685,146 @@ var UsersClient = class {
);
}
/**
- * Follow List
- * Causes the authenticated user to follow a specific List by its ID.
+ * Search Spaces
+ * Retrieves a list of Spaces matching the specified search query.
- * @param id The ID of the authenticated source User that will follow the List.
+ * @param query The search query.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async followList(id, options = {}) {
- const normalizedOptions = options || {};
+ async search(query, options = {}) {
+ const paramMappings = {
+ max_results: "maxResults",
+ "space.fields": "spaceFields",
+ "user.fields": "userFields",
+ "topic.fields": "topicFields"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
const {
- body,
+ state = void 0,
+ maxResults = void 0,
+ spaceFields = [],
+ expansions = [],
+ userFields = [],
+ topicFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/{id}/followed_lists";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/spaces/search";
const params = new URLSearchParams();
+ if (query !== void 0) {
+ params.append("query", String(query));
+ }
+ if (state !== void 0) {
+ params.append("state", String(state));
+ }
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
+ }
+ if (spaceFields !== void 0 && spaceFields.length > 0) {
+ params.append("space.fields", spaceFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (topicFields !== void 0 && topicFields.length > 0) {
+ params.append("topic.fields", topicFields.join(","));
+ }
const finalRequestOptions = {
- body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["list.write", "tweet.read", "users.read"]
+ BearerToken: []
},
{
- UserToken: []
+ OAuth2UserToken: ["space.read", "tweet.read", "users.read"]
}
],
...requestOptions
};
return this.client.request(
- "POST",
+ "GET",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
+};
+
+// src/spaces/models.ts
+var models_exports5 = {};
+
+// src/trends/client.ts
+var TrendsClient = class {
+ client;
/**
- * Like Post
- * Causes the authenticated user to Like a specific Post by its ID.
-
-
- * @param id The ID of the authenticated source User that is requesting to like the Post.
-
+ * Creates a new trends client instance
+ *
+ * @param client - The main X API client instance
+ */
+ constructor(client) {
+ this.client = client;
+ }
+ /**
+ * Normalize options object to handle both camelCase and original API parameter names
+ * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
+ */
+ _normalizeOptions(options, paramMappings) {
+ if (!options || typeof options !== "object") {
+ return options;
+ }
+ const normalized = { ...options };
+ for (const [originalName, camelName] of Object.entries(paramMappings)) {
+ if (originalName in normalized && !(camelName in normalized)) {
+ normalized[camelName] = normalized[originalName];
+ delete normalized[originalName];
+ }
+ }
+ return normalized;
+ }
+ /**
+ * Get personalized Trends
+ * Retrieves personalized trending topics for the authenticated user.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async likePost(id, options = {}) {
- const normalizedOptions = options || {};
+ async getPersonalized(options = {}) {
+ const paramMappings = {
+ "personalized_trend.fields": "personalizedTrendFields"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
const {
- body,
+ personalizedTrendFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/{id}/likes";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/users/personalized_trends";
const params = new URLSearchParams();
+ if (personalizedTrendFields !== void 0 && personalizedTrendFields.length > 0) {
+ params.append(
+ "personalized_trend.fields",
+ personalizedTrendFields.join(",")
+ );
+ }
const finalRequestOptions = {
- body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["like.write", "tweet.read", "users.read"]
+ OAuth2UserToken: ["tweet.read", "users.read"]
},
{
UserToken: []
@@ -7999,84 +7833,52 @@ var UsersClient = class {
...requestOptions
};
return this.client.request(
- "POST",
+ "GET",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get liked Posts
- * Retrieves a list of Posts liked by a specific User by their ID.
+ * Get Trends by WOEID
+ * Retrieves trending topics for a specific location identified by its WOEID.
- * @param id The ID of the User to lookup.
+ * @param woeid The WOEID of the place to lookup a trend for.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getLikedPosts(id, options = {}) {
+ async getByWoeid(woeid, options = {}) {
const paramMappings = {
- max_results: "maxResults",
- pagination_token: "paginationToken",
- "tweet.fields": "tweetFields",
- "media.fields": "mediaFields",
- "poll.fields": "pollFields",
- "user.fields": "userFields",
- "place.fields": "placeFields"
+ max_trends: "maxTrends",
+ "trend.fields": "trendFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- maxResults = void 0,
- paginationToken = void 0,
- tweetFields = [],
- expansions = [],
- mediaFields = [],
- pollFields = [],
- userFields = [],
- placeFields = [],
+ maxTrends = void 0,
+ trendFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/{id}/liked_tweets";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/trends/by/woeid/{woeid}";
+ path = path.replace("{woeid}", encodeURIComponent(String(woeid)));
const params = new URLSearchParams();
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
- }
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (mediaFields !== void 0 && mediaFields.length > 0) {
- params.append("media.fields", mediaFields.join(","));
- }
- if (pollFields !== void 0 && pollFields.length > 0) {
- params.append("poll.fields", pollFields.join(","));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
+ if (maxTrends !== void 0) {
+ params.append("max_trends", String(maxTrends));
}
- if (placeFields !== void 0 && placeFields.length > 0) {
- params.append("place.fields", placeFields.join(","));
+ if (trendFields !== void 0 && trendFields.length > 0) {
+ params.append("trend.fields", trendFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["like.read", "tweet.read", "users.read"]
- },
- {
- UserToken: []
+ BearerToken: []
}
],
...requestOptions
@@ -8088,46 +7890,114 @@ var UsersClient = class {
);
}
/**
- * Get Users by usernames
- * Retrieves details of multiple Users by their usernames.
+ * Get AI Trends by ID
+ * Retrieves an AI trend by its ID.
+ * @param id The ID of the ai trend.
- * @param usernames A list of usernames, comma-separated.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getByUsernames(usernames, options = {}) {
+ async getAi(id, options = {}) {
const paramMappings = {
- "user.fields": "userFields",
- "tweet.fields": "tweetFields"
+ "news.fields": "newsFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- userFields = [],
- expansions = [],
- tweetFields = [],
+ newsFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/by";
+ let path = "/2/ai_trends/{id}";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (usernames !== void 0 && usernames.length > 0) {
- params.append("usernames", usernames.join(","));
+ if (newsFields !== void 0 && newsFields.length > 0) {
+ params.append("news.fields", newsFields.join(","));
}
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
+ const finalRequestOptions = {
+ // Pass security requirements for smart auth selection
+ security: [
+ {
+ BearerToken: []
+ }
+ ],
+ ...requestOptions
+ };
+ return this.client.request(
+ "GET",
+ path + (params.toString() ? `?${params.toString()}` : ""),
+ finalRequestOptions
+ );
+ }
+};
+
+// src/trends/models.ts
+var models_exports6 = {};
+
+// src/media/client.ts
+var MediaClient = class {
+ client;
+ /**
+ * Creates a new media client instance
+ *
+ * @param client - The main X API client instance
+ */
+ constructor(client) {
+ this.client = client;
+ }
+ /**
+ * Normalize options object to handle both camelCase and original API parameter names
+ * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
+ */
+ _normalizeOptions(options, paramMappings) {
+ if (!options || typeof options !== "object") {
+ return options;
}
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
+ const normalized = { ...options };
+ for (const [originalName, camelName] of Object.entries(paramMappings)) {
+ if (originalName in normalized && !(camelName in normalized)) {
+ normalized[camelName] = normalized[originalName];
+ delete normalized[originalName];
+ }
}
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ return normalized;
+ }
+ /**
+ * Get Media by media key
+ * Retrieves details of a specific Media file by its media key.
+
+
+ * @param mediaKey A single Media Key.
+
+
+
+
+ * @returns {Promise} Promise resolving to the API response
+ */
+ // Overload 1: Default behavior (unwrapped response)
+ async getByKey(mediaKey, options = {}) {
+ const paramMappings = {
+ "media.fields": "mediaFields"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
+ const {
+ mediaFields = [],
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/media/{media_key}";
+ path = path.replace("{media_key}", encodeURIComponent(String(mediaKey)));
+ const params = new URLSearchParams();
+ if (mediaFields !== void 0 && mediaFields.length > 0) {
+ params.append("media.fields", mediaFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
@@ -8136,7 +8006,7 @@ var UsersClient = class {
BearerToken: []
},
{
- OAuth2UserToken: ["tweet.read", "users.read"]
+ OAuth2UserToken: ["tweet.read"]
},
{
UserToken: []
@@ -8151,33 +8021,28 @@ var UsersClient = class {
);
}
/**
- * Repost Post
- * Causes the authenticated user to repost a specific Post by its ID.
-
-
- * @param id The ID of the authenticated source User that is requesting to repost the Post.
-
+ * Create Media metadata
+ * Creates metadata for a Media file.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async repostPost(id, options = {}) {
+ async createMetadata(options = {}) {
const normalizedOptions = options || {};
const {
body,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/{id}/retweets";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/media/metadata";
const params = new URLSearchParams();
const finalRequestOptions = {
body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["tweet.read", "tweet.write", "users.read"]
+ OAuth2UserToken: ["media.write"]
},
{
UserToken: []
@@ -8192,38 +8057,27 @@ var UsersClient = class {
);
}
/**
- * Unfollow User
- * Causes the authenticated user to unfollow a specific user by their ID.
-
-
- * @param sourceUserId The ID of the authenticated source User that is requesting to unfollow the target User.
-
+ * Finalize Media upload
+ * Finalizes a Media upload request.
- * @param targetUserId The ID of the User that the source User is requesting to unfollow.
+ * @param id The media id of the targeted media to finalize.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async unfollowUser(sourceUserId, targetUserId) {
- let path = "/2/users/{source_user_id}/following/{target_user_id}";
- path = path.replace(
- "{source_user_id}",
- encodeURIComponent(String(sourceUserId))
- );
- path = path.replace(
- "{target_user_id}",
- encodeURIComponent(String(targetUserId))
- );
+ async finalizeUpload(id) {
+ let path = "/2/media/upload/{id}/finalize";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["follows.write", "tweet.read", "users.read"]
+ OAuth2UserToken: ["media.write"]
},
{
UserToken: []
@@ -8232,69 +8086,75 @@ var UsersClient = class {
// No optional parameters, using empty request options
};
return this.client.request(
- "DELETE",
+ "POST",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get followers
- * Retrieves a list of Users who follow a specific User by their ID.
+ * Append Media upload
+ * Appends data to a Media upload request.
- * @param id The ID of the User to lookup.
+ * @param id The media identifier for the media to perform the append operation.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getFollowers(id, options = {}) {
- const paramMappings = {
- max_results: "maxResults",
- pagination_token: "paginationToken",
- "user.fields": "userFields",
- "tweet.fields": "tweetFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
+ async appendUpload(id, options = {}) {
+ const normalizedOptions = options || {};
const {
- maxResults = void 0,
- paginationToken = void 0,
- userFields = [],
- expansions = [],
- tweetFields = [],
+ body,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/{id}/followers";
+ let path = "/2/media/upload/{id}/append";
path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
- }
const finalRequestOptions = {
+ body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
+ OAuth2UserToken: ["media.write"]
},
{
- OAuth2UserToken: ["follows.read", "tweet.read", "users.read"]
+ UserToken: []
+ }
+ ],
+ ...requestOptions
+ };
+ return this.client.request(
+ "POST",
+ path + (params.toString() ? `?${params.toString()}` : ""),
+ finalRequestOptions
+ );
+ }
+ /**
+ * Initialize media upload
+ * Initializes a media upload.
+
+
+
+ * @returns {Promise} Promise resolving to the API response
+ */
+ // Overload 1: Default behavior (unwrapped response)
+ async initializeUpload(options = {}) {
+ const normalizedOptions = options || {};
+ const {
+ body,
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/media/upload/initialize";
+ const params = new URLSearchParams();
+ const finalRequestOptions = {
+ body: body ? JSON.stringify(body) : void 0,
+ // Pass security requirements for smart auth selection
+ security: [
+ {
+ OAuth2UserToken: ["media.write"]
},
{
UserToken: []
@@ -8303,52 +8163,43 @@ var UsersClient = class {
...requestOptions
};
return this.client.request(
- "GET",
+ "POST",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get Users by IDs
- * Retrieves details of multiple Users by their IDs.
+ * Get Media by media keys
+ * Retrieves details of Media files by their media keys.
- * @param ids A list of User IDs, comma-separated. You can specify up to 100 IDs.
+ * @param mediaKeys A comma separated list of Media Keys. Up to 100 are allowed in a single request.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getByIds(ids, options = {}) {
+ async getByKeys(mediaKeys, options = {}) {
const paramMappings = {
- "user.fields": "userFields",
- "tweet.fields": "tweetFields"
+ "media.fields": "mediaFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- userFields = [],
- expansions = [],
- tweetFields = [],
+ mediaFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users";
+ let path = "/2/media";
const params = new URLSearchParams();
- if (ids !== void 0 && ids.length > 0) {
- params.append("ids", ids.join(","));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
+ if (mediaKeys !== void 0 && mediaKeys.length > 0) {
+ params.append("media_keys", mediaKeys.join(","));
}
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ if (mediaFields !== void 0 && mediaFields.length > 0) {
+ params.append("media.fields", mediaFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
@@ -8357,7 +8208,7 @@ var UsersClient = class {
BearerToken: []
},
{
- OAuth2UserToken: ["tweet.read", "users.read"]
+ OAuth2UserToken: ["tweet.read"]
},
{
UserToken: []
@@ -8372,35 +8223,47 @@ var UsersClient = class {
);
}
/**
- * Get Bookmarks by folder ID
- * Retrieves Posts in a specific Bookmark folder by its ID for the authenticated user.
-
-
- * @param id The ID of the authenticated source User for whom to return results.
-
+ * Get Media upload status
+ * Retrieves the status of a Media upload by its ID.
- * @param folderId The ID of the Bookmark Folder that the authenticated User is trying to fetch Posts for.
+ * @param mediaId Media id for the requested media upload status.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getBookmarksByFolderId(id, folderId) {
- let path = "/2/users/{id}/bookmarks/folders/{folder_id}";
- path = path.replace("{id}", encodeURIComponent(String(id)));
- path = path.replace("{folder_id}", encodeURIComponent(String(folderId)));
+ async getUploadStatus(mediaId, options = {}) {
+ const paramMappings = {};
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
+ const {
+ command = void 0,
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/media/upload";
const params = new URLSearchParams();
+ if (mediaId !== void 0) {
+ params.append("media_id", String(mediaId));
+ }
+ if (command !== void 0) {
+ params.append("command", String(command));
+ }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["bookmark.read", "tweet.read", "users.read"]
+ OAuth2UserToken: ["media.write"]
+ },
+ {
+ UserToken: []
}
- ]
- // No optional parameters, using empty request options
+ ],
+ ...requestOptions
};
return this.client.request(
"GET",
@@ -8409,114 +8272,100 @@ var UsersClient = class {
);
}
/**
- * Get Bookmark folders
- * Retrieves a list of Bookmark folders created by the authenticated user.
-
-
- * @param id The ID of the authenticated source User for whom to return results.
-
+ * Upload media
+ * Uploads a media file for use in posts or other content.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getBookmarkFolders(id, options = {}) {
- const paramMappings = {
- max_results: "maxResults",
- pagination_token: "paginationToken"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
+ async upload(options = {}) {
+ const normalizedOptions = options || {};
const {
- maxResults = void 0,
- paginationToken = void 0,
+ body,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/{id}/bookmarks/folders";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/media/upload";
const params = new URLSearchParams();
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
- }
const finalRequestOptions = {
+ body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["bookmark.read", "users.read"]
+ OAuth2UserToken: ["media.write"]
+ },
+ {
+ UserToken: []
}
],
...requestOptions
};
return this.client.request(
- "GET",
+ "POST",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get following
- * Retrieves a list of Users followed by a specific User by their ID.
+ * Get Media analytics
+ * Retrieves analytics data for media.
- * @param id The ID of the User to lookup.
+ * @param mediaKeys A comma separated list of Media Keys. Up to 100 are allowed in a single request.
- * @returns {Promise} Promise resolving to the API response
+ * @param endTime YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range.
+
+
+
+ * @param startTime YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range.
+
+
+
+ * @param granularity The granularity for the search counts results.
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getFollowing(id, options = {}) {
+ async getAnalytics(mediaKeys, endTime, startTime, granularity, options = {}) {
const paramMappings = {
- max_results: "maxResults",
- pagination_token: "paginationToken",
- "user.fields": "userFields",
- "tweet.fields": "tweetFields"
+ "media_analytics.fields": "mediaAnalyticsFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- maxResults = void 0,
- paginationToken = void 0,
- userFields = [],
- expansions = [],
- tweetFields = [],
+ mediaAnalyticsFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/{id}/following";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/media/analytics";
const params = new URLSearchParams();
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
+ if (mediaKeys !== void 0 && mediaKeys.length > 0) {
+ params.append("media_keys", mediaKeys.join(","));
}
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
+ if (endTime !== void 0) {
+ params.append("end_time", String(endTime));
}
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
+ if (startTime !== void 0) {
+ params.append("start_time", String(startTime));
}
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
+ if (granularity !== void 0) {
+ params.append("granularity", String(granularity));
}
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ if (mediaAnalyticsFields !== void 0 && mediaAnalyticsFields.length > 0) {
+ params.append("media_analytics.fields", mediaAnalyticsFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
- },
- {
- OAuth2UserToken: ["follows.read", "tweet.read", "users.read"]
+ OAuth2UserToken: ["tweet.read"]
},
{
UserToken: []
@@ -8531,33 +8380,28 @@ var UsersClient = class {
);
}
/**
- * Follow User
- * Causes the authenticated user to follow a specific user by their ID.
-
-
- * @param id The ID of the authenticated source User that is requesting to follow the target User.
-
+ * Create Media subtitles
+ * Creates subtitles for a specific Media file.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async followUser(id, options = {}) {
+ async createSubtitles(options = {}) {
const normalizedOptions = options || {};
const {
body,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/{id}/following";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/media/subtitles";
const params = new URLSearchParams();
const finalRequestOptions = {
body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["follows.write", "tweet.read", "users.read"]
+ OAuth2UserToken: ["media.write"]
},
{
UserToken: []
@@ -8572,99 +8416,28 @@ var UsersClient = class {
);
}
/**
- * Get Timeline
- * Retrieves a reverse chronological list of Posts in the authenticated User’s Timeline.
-
-
- * @param id The ID of the authenticated source User to list Reverse Chronological Timeline Posts of.
-
+ * Delete Media subtitles
+ * Deletes subtitles for a specific Media file.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getTimeline(id, options = {}) {
- const paramMappings = {
- since_id: "sinceId",
- until_id: "untilId",
- max_results: "maxResults",
- pagination_token: "paginationToken",
- start_time: "startTime",
- end_time: "endTime",
- "tweet.fields": "tweetFields",
- "media.fields": "mediaFields",
- "poll.fields": "pollFields",
- "user.fields": "userFields",
- "place.fields": "placeFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
+ async deleteSubtitles(options = {}) {
+ const normalizedOptions = options || {};
const {
- sinceId = void 0,
- untilId = void 0,
- maxResults = void 0,
- paginationToken = void 0,
- exclude = [],
- startTime = void 0,
- endTime = void 0,
- tweetFields = [],
- expansions = [],
- mediaFields = [],
- pollFields = [],
- userFields = [],
- placeFields = [],
+ body,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/{id}/timelines/reverse_chronological";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/media/subtitles";
const params = new URLSearchParams();
- if (sinceId !== void 0) {
- params.append("since_id", String(sinceId));
- }
- if (untilId !== void 0) {
- params.append("until_id", String(untilId));
- }
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
- }
- if (exclude !== void 0 && exclude.length > 0) {
- params.append("exclude", exclude.join(","));
- }
- if (startTime !== void 0) {
- params.append("start_time", String(startTime));
- }
- if (endTime !== void 0) {
- params.append("end_time", String(endTime));
- }
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (mediaFields !== void 0 && mediaFields.length > 0) {
- params.append("media.fields", mediaFields.join(","));
- }
- if (pollFields !== void 0 && pollFields.length > 0) {
- params.append("poll.fields", pollFields.join(","));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (placeFields !== void 0 && placeFields.length > 0) {
- params.append("place.fields", placeFields.join(","));
- }
const finalRequestOptions = {
+ body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["tweet.read", "users.read"]
+ OAuth2UserToken: ["media.write"]
},
{
UserToken: []
@@ -8673,29 +8446,71 @@ var UsersClient = class {
...requestOptions
};
return this.client.request(
- "GET",
+ "DELETE",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
+};
+
+// src/media/models.ts
+var models_exports7 = {};
+
+// src/direct_messages/client.ts
+var DirectMessagesClient = class {
+ client;
/**
- * Unblock DMs
- * Unblocks direct messages to or from a specific User by their ID for the authenticated user.
+ * Creates a new direct messages client instance
+ *
+ * @param client - The main X API client instance
+ */
+ constructor(client) {
+ this.client = client;
+ }
+ /**
+ * Normalize options object to handle both camelCase and original API parameter names
+ * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
+ */
+ _normalizeOptions(options, paramMappings) {
+ if (!options || typeof options !== "object") {
+ return options;
+ }
+ const normalized = { ...options };
+ for (const [originalName, camelName] of Object.entries(paramMappings)) {
+ if (originalName in normalized && !(camelName in normalized)) {
+ normalized[camelName] = normalized[originalName];
+ delete normalized[originalName];
+ }
+ }
+ return normalized;
+ }
+ /**
+ * Create DM message by participant ID
+ * Sends a new direct message to a specific participant by their ID.
- * @param id The ID of the target User that the authenticated user requesting to unblock dms for.
+ * @param participantId The ID of the recipient user that will receive the DM.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async unblockDms(id) {
- let path = "/2/users/{id}/dm/unblock";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ async createByParticipantId(participantId, options = {}) {
+ const normalizedOptions = options || {};
+ const {
+ body,
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/dm_conversations/with/{participant_id}/messages";
+ path = path.replace(
+ "{participant_id}",
+ encodeURIComponent(String(participantId))
+ );
const params = new URLSearchParams();
const finalRequestOptions = {
+ body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
@@ -8704,8 +8519,8 @@ var UsersClient = class {
{
UserToken: []
}
- ]
- // No optional parameters, using empty request options
+ ],
+ ...requestOptions
};
return this.client.request(
"POST",
@@ -8714,74 +8529,52 @@ var UsersClient = class {
);
}
/**
- * Get mentions
- * Retrieves a list of Posts that mention a specific User by their ID.
-
-
- * @param id The ID of the User to lookup.
-
+ * Get DM events
+ * Retrieves a list of recent direct message events across all conversations.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getMentions(id, options = {}) {
+ async getEvents(options = {}) {
const paramMappings = {
- since_id: "sinceId",
- until_id: "untilId",
max_results: "maxResults",
pagination_token: "paginationToken",
- start_time: "startTime",
- end_time: "endTime",
- "tweet.fields": "tweetFields",
+ event_types: "eventTypes",
+ "dm_event.fields": "dmEventFields",
"media.fields": "mediaFields",
- "poll.fields": "pollFields",
"user.fields": "userFields",
- "place.fields": "placeFields"
+ "tweet.fields": "tweetFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- sinceId = void 0,
- untilId = void 0,
maxResults = void 0,
paginationToken = void 0,
- startTime = void 0,
- endTime = void 0,
- tweetFields = [],
+ eventTypes = [],
+ dmEventFields = [],
expansions = [],
mediaFields = [],
- pollFields = [],
userFields = [],
- placeFields = [],
+ tweetFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/{id}/mentions";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/dm_events";
const params = new URLSearchParams();
- if (sinceId !== void 0) {
- params.append("since_id", String(sinceId));
- }
- if (untilId !== void 0) {
- params.append("until_id", String(untilId));
- }
if (maxResults !== void 0) {
params.append("max_results", String(maxResults));
}
if (paginationToken !== void 0) {
params.append("pagination_token", String(paginationToken));
}
- if (startTime !== void 0) {
- params.append("start_time", String(startTime));
- }
- if (endTime !== void 0) {
- params.append("end_time", String(endTime));
+ if (eventTypes !== void 0 && eventTypes.length > 0) {
+ params.append("event_types", eventTypes.join(","));
}
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ if (dmEventFields !== void 0 && dmEventFields.length > 0) {
+ params.append("dm_event.fields", dmEventFields.join(","));
}
if (expansions !== void 0 && expansions.length > 0) {
params.append("expansions", expansions.join(","));
@@ -8789,23 +8582,17 @@ var UsersClient = class {
if (mediaFields !== void 0 && mediaFields.length > 0) {
params.append("media.fields", mediaFields.join(","));
}
- if (pollFields !== void 0 && pollFields.length > 0) {
- params.append("poll.fields", pollFields.join(","));
- }
if (userFields !== void 0 && userFields.length > 0) {
params.append("user.fields", userFields.join(","));
}
- if (placeFields !== void 0 && placeFields.length > 0) {
- params.append("place.fields", placeFields.join(","));
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
- },
- {
- OAuth2UserToken: ["tweet.read", "users.read"]
+ OAuth2UserToken: ["dm.read", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -8820,24 +8607,27 @@ var UsersClient = class {
);
}
/**
- * Get List memberships
- * Retrieves a list of Lists that a specific User is a member of by their ID.
+ * Get DM events for a DM conversation
+ * Retrieves direct message events for a specific conversation.
- * @param id The ID of the User to lookup.
+ * @param participantId The ID of the participant user for the One to One DM conversation.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getListMemberships(id, options = {}) {
+ async getEventsByParticipantId(participantId, options = {}) {
const paramMappings = {
max_results: "maxResults",
pagination_token: "paginationToken",
- "list.fields": "listFields",
- "user.fields": "userFields"
+ event_types: "eventTypes",
+ "dm_event.fields": "dmEventFields",
+ "media.fields": "mediaFields",
+ "user.fields": "userFields",
+ "tweet.fields": "tweetFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
@@ -8846,13 +8636,19 @@ var UsersClient = class {
const {
maxResults = void 0,
paginationToken = void 0,
- listFields = [],
+ eventTypes = [],
+ dmEventFields = [],
expansions = [],
+ mediaFields = [],
userFields = [],
+ tweetFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/{id}/list_memberships";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/dm_conversations/with/{participant_id}/dm_events";
+ path = path.replace(
+ "{participant_id}",
+ encodeURIComponent(String(participantId))
+ );
const params = new URLSearchParams();
if (maxResults !== void 0) {
params.append("max_results", String(maxResults));
@@ -8860,23 +8656,29 @@ var UsersClient = class {
if (paginationToken !== void 0) {
params.append("pagination_token", String(paginationToken));
}
- if (listFields !== void 0 && listFields.length > 0) {
- params.append("list.fields", listFields.join(","));
+ if (eventTypes !== void 0 && eventTypes.length > 0) {
+ params.append("event_types", eventTypes.join(","));
+ }
+ if (dmEventFields !== void 0 && dmEventFields.length > 0) {
+ params.append("dm_event.fields", dmEventFields.join(","));
}
if (expansions !== void 0 && expansions.length > 0) {
params.append("expansions", expansions.join(","));
}
+ if (mediaFields !== void 0 && mediaFields.length > 0) {
+ params.append("media.fields", mediaFields.join(","));
+ }
if (userFields !== void 0 && userFields.length > 0) {
params.append("user.fields", userFields.join(","));
}
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
- },
- {
- OAuth2UserToken: ["list.read", "tweet.read", "users.read"]
+ OAuth2UserToken: ["dm.read", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -8891,23 +8693,27 @@ var UsersClient = class {
);
}
/**
- * Get Reposts of me
- * Retrieves a list of Posts that repost content from the authenticated user.
+ * Get DM events for a DM conversation
+ * Retrieves direct message events for a specific conversation.
+
+ * @param id The DM conversation ID.
- * @returns {Promise} Promise resolving to the API response
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getRepostsOfMe(options = {}) {
+ async getEventsByConversationId(id, options = {}) {
const paramMappings = {
max_results: "maxResults",
pagination_token: "paginationToken",
- "tweet.fields": "tweetFields",
+ event_types: "eventTypes",
+ "dm_event.fields": "dmEventFields",
"media.fields": "mediaFields",
- "poll.fields": "pollFields",
"user.fields": "userFields",
- "place.fields": "placeFields"
+ "tweet.fields": "tweetFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
@@ -8916,15 +8722,16 @@ var UsersClient = class {
const {
maxResults = void 0,
paginationToken = void 0,
- tweetFields = [],
+ eventTypes = [],
+ dmEventFields = [],
expansions = [],
mediaFields = [],
- pollFields = [],
userFields = [],
- placeFields = [],
+ tweetFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/reposts_of_me";
+ let path = "/2/dm_conversations/{id}/dm_events";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
if (maxResults !== void 0) {
params.append("max_results", String(maxResults));
@@ -8932,8 +8739,11 @@ var UsersClient = class {
if (paginationToken !== void 0) {
params.append("pagination_token", String(paginationToken));
}
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ if (eventTypes !== void 0 && eventTypes.length > 0) {
+ params.append("event_types", eventTypes.join(","));
+ }
+ if (dmEventFields !== void 0 && dmEventFields.length > 0) {
+ params.append("dm_event.fields", dmEventFields.join(","));
}
if (expansions !== void 0 && expansions.length > 0) {
params.append("expansions", expansions.join(","));
@@ -8941,20 +8751,17 @@ var UsersClient = class {
if (mediaFields !== void 0 && mediaFields.length > 0) {
params.append("media.fields", mediaFields.join(","));
}
- if (pollFields !== void 0 && pollFields.length > 0) {
- params.append("poll.fields", pollFields.join(","));
- }
if (userFields !== void 0 && userFields.length > 0) {
params.append("user.fields", userFields.join(","));
}
- if (placeFields !== void 0 && placeFields.length > 0) {
- params.append("place.fields", placeFields.join(","));
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["timeline.read", "tweet.read"]
+ OAuth2UserToken: ["dm.read", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -8968,57 +8775,21 @@ var UsersClient = class {
finalRequestOptions
);
}
-};
-
-// src/users/models.ts
-var models_exports2 = {};
-
-// src/direct_messages/client.ts
-var DirectMessagesClient = class {
- client;
- /**
- * Creates a new direct messages client instance
- *
- * @param client - The main X API client instance
- */
- constructor(client) {
- this.client = client;
- }
- /**
- * Normalize options object to handle both camelCase and original API parameter names
- * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
- */
- _normalizeOptions(options, paramMappings) {
- if (!options || typeof options !== "object") {
- return options;
- }
- const normalized = { ...options };
- for (const [originalName, camelName] of Object.entries(paramMappings)) {
- if (originalName in normalized && !(camelName in normalized)) {
- normalized[camelName] = normalized[originalName];
- delete normalized[originalName];
- }
- }
- return normalized;
- }
/**
- * Get DM events for a DM conversation
- * Retrieves direct message events for a specific conversation.
+ * Get DM event by ID
+ * Retrieves details of a specific direct message event by its ID.
- * @param participantId The ID of the participant user for the One to One DM conversation.
+ * @param eventId dm event id.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getEventsByParticipantId(participantId, options = {}) {
+ async getEventsById(eventId, options = {}) {
const paramMappings = {
- max_results: "maxResults",
- pagination_token: "paginationToken",
- event_types: "eventTypes",
"dm_event.fields": "dmEventFields",
"media.fields": "mediaFields",
"user.fields": "userFields",
@@ -9029,9 +8800,6 @@ var DirectMessagesClient = class {
paramMappings
);
const {
- maxResults = void 0,
- paginationToken = void 0,
- eventTypes = [],
dmEventFields = [],
expansions = [],
mediaFields = [],
@@ -9039,21 +8807,9 @@ var DirectMessagesClient = class {
tweetFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/dm_conversations/with/{participant_id}/dm_events";
- path = path.replace(
- "{participant_id}",
- encodeURIComponent(String(participantId))
- );
+ let path = "/2/dm_events/{event_id}";
+ path = path.replace("{event_id}", encodeURIComponent(String(eventId)));
const params = new URLSearchParams();
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
- }
- if (eventTypes !== void 0 && eventTypes.length > 0) {
- params.append("event_types", eventTypes.join(","));
- }
if (dmEventFields !== void 0 && dmEventFields.length > 0) {
params.append("dm_event.fields", dmEventFields.join(","));
}
@@ -9088,72 +8844,63 @@ var DirectMessagesClient = class {
);
}
/**
- * Create DM message by conversation ID
- * Sends a new direct message to a specific conversation by its ID.
+ * Delete DM event
+ * Deletes a specific direct message event by its ID, if owned by the authenticated user.
- * @param dmConversationId The DM Conversation ID.
+ * @param eventId The ID of the direct-message event to delete.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async createByConversationId(dmConversationId, options = {}) {
- const normalizedOptions = options || {};
- const {
- body,
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/dm_conversations/{dm_conversation_id}/messages";
- path = path.replace(
- "{dm_conversation_id}",
- encodeURIComponent(String(dmConversationId))
- );
+ async deleteEvents(eventId) {
+ let path = "/2/dm_events/{event_id}";
+ path = path.replace("{event_id}", encodeURIComponent(String(eventId)));
const params = new URLSearchParams();
const finalRequestOptions = {
- body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["dm.write", "tweet.read", "users.read"]
+ OAuth2UserToken: ["dm.read", "dm.write"]
},
{
UserToken: []
}
- ],
- ...requestOptions
+ ]
+ // No optional parameters, using empty request options
};
return this.client.request(
- "POST",
+ "DELETE",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Create DM message by participant ID
- * Sends a new direct message to a specific participant by their ID.
+ * Create DM message by conversation ID
+ * Sends a new direct message to a specific conversation by its ID.
- * @param participantId The ID of the recipient user that will receive the DM.
+ * @param dmConversationId The DM Conversation ID.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async createByParticipantId(participantId, options = {}) {
+ async createByConversationId(dmConversationId, options = {}) {
const normalizedOptions = options || {};
const {
body,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/dm_conversations/with/{participant_id}/messages";
+ let path = "/2/dm_conversations/{dm_conversation_id}/messages";
path = path.replace(
- "{participant_id}",
- encodeURIComponent(String(participantId))
+ "{dm_conversation_id}",
+ encodeURIComponent(String(dmConversationId))
);
const params = new URLSearchParams();
const finalRequestOptions = {
@@ -9211,61 +8958,91 @@ var DirectMessagesClient = class {
finalRequestOptions
);
}
+};
+
+// src/direct_messages/models.ts
+var models_exports8 = {};
+
+// src/posts/client.ts
+var PostsClient = class {
+ client;
+ /**
+ * Creates a new posts client instance
+ *
+ * @param client - The main X API client instance
+ */
+ constructor(client) {
+ this.client = client;
+ }
/**
- * Get DM event by ID
- * Retrieves details of a specific direct message event by its ID.
+ * Normalize options object to handle both camelCase and original API parameter names
+ * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
+ */
+ _normalizeOptions(options, paramMappings) {
+ if (!options || typeof options !== "object") {
+ return options;
+ }
+ const normalized = { ...options };
+ for (const [originalName, camelName] of Object.entries(paramMappings)) {
+ if (originalName in normalized && !(camelName in normalized)) {
+ normalized[camelName] = normalized[originalName];
+ delete normalized[originalName];
+ }
+ }
+ return normalized;
+ }
+ /**
+ * Get 28-hour Post insights
+ * Retrieves engagement metrics for specified Posts over the last 28 hours.
- * @param eventId dm event id.
+ * @param tweetIds List of PostIds for 28hr metrics.
- * @returns {Promise} Promise resolving to the API response
+ * @param granularity granularity of metrics response.
+
+
+
+ * @param requestedMetrics request metrics for historical request.
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getEventsById(eventId, options = {}) {
+ async getInsights28hr(tweetIds, granularity, requestedMetrics, options = {}) {
const paramMappings = {
- "dm_event.fields": "dmEventFields",
- "media.fields": "mediaFields",
- "user.fields": "userFields",
- "tweet.fields": "tweetFields"
+ "engagement.fields": "engagementFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- dmEventFields = [],
- expansions = [],
- mediaFields = [],
- userFields = [],
- tweetFields = [],
+ engagementFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/dm_events/{event_id}";
- path = path.replace("{event_id}", encodeURIComponent(String(eventId)));
+ let path = "/2/insights/28hr";
const params = new URLSearchParams();
- if (dmEventFields !== void 0 && dmEventFields.length > 0) {
- params.append("dm_event.fields", dmEventFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
+ if (tweetIds !== void 0 && tweetIds.length > 0) {
+ params.append("tweet_ids", tweetIds.join(","));
}
- if (mediaFields !== void 0 && mediaFields.length > 0) {
- params.append("media.fields", mediaFields.join(","));
+ if (granularity !== void 0) {
+ params.append("granularity", String(granularity));
}
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
+ if (requestedMetrics !== void 0 && requestedMetrics.length > 0) {
+ params.append("requested_metrics", requestedMetrics.join(","));
}
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ if (engagementFields !== void 0 && engagementFields.length > 0) {
+ params.append("engagement.fields", engagementFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["dm.read", "tweet.read", "users.read"]
+ OAuth2UserToken: ["tweet.read"]
},
{
UserToken: []
@@ -9280,58 +9057,27 @@ var DirectMessagesClient = class {
);
}
/**
- * Delete DM event
- * Deletes a specific direct message event by its ID, if owned by the authenticated user.
+ * Get Reposts
+ * Retrieves a list of Posts that repost a specific Post by its ID.
- * @param eventId The ID of the direct-message event to delete.
+ * @param id A single Post ID.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async deleteEvents(eventId) {
- let path = "/2/dm_events/{event_id}";
- path = path.replace("{event_id}", encodeURIComponent(String(eventId)));
- const params = new URLSearchParams();
- const finalRequestOptions = {
- // Pass security requirements for smart auth selection
- security: [
- {
- OAuth2UserToken: ["dm.read", "dm.write"]
- },
- {
- UserToken: []
- }
- ]
- // No optional parameters, using empty request options
- };
- return this.client.request(
- "DELETE",
- path + (params.toString() ? `?${params.toString()}` : ""),
- finalRequestOptions
- );
- }
- /**
- * Get DM events
- * Retrieves a list of recent direct message events across all conversations.
-
-
-
- * @returns {Promise} Promise resolving to the API response
- */
- // Overload 1: Default behavior (unwrapped response)
- async getEvents(options = {}) {
+ async getReposts(id, options = {}) {
const paramMappings = {
max_results: "maxResults",
pagination_token: "paginationToken",
- event_types: "eventTypes",
- "dm_event.fields": "dmEventFields",
+ "tweet.fields": "tweetFields",
"media.fields": "mediaFields",
+ "poll.fields": "pollFields",
"user.fields": "userFields",
- "tweet.fields": "tweetFields"
+ "place.fields": "placeFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
@@ -9340,15 +9086,16 @@ var DirectMessagesClient = class {
const {
maxResults = void 0,
paginationToken = void 0,
- eventTypes = [],
- dmEventFields = [],
+ tweetFields = [],
expansions = [],
mediaFields = [],
+ pollFields = [],
userFields = [],
- tweetFields = [],
+ placeFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/dm_events";
+ let path = "/2/tweets/{id}/retweets";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
if (maxResults !== void 0) {
params.append("max_results", String(maxResults));
@@ -9356,11 +9103,8 @@ var DirectMessagesClient = class {
if (paginationToken !== void 0) {
params.append("pagination_token", String(paginationToken));
}
- if (eventTypes !== void 0 && eventTypes.length > 0) {
- params.append("event_types", eventTypes.join(","));
- }
- if (dmEventFields !== void 0 && dmEventFields.length > 0) {
- params.append("dm_event.fields", dmEventFields.join(","));
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
}
if (expansions !== void 0 && expansions.length > 0) {
params.append("expansions", expansions.join(","));
@@ -9368,17 +9112,23 @@ var DirectMessagesClient = class {
if (mediaFields !== void 0 && mediaFields.length > 0) {
params.append("media.fields", mediaFields.join(","));
}
+ if (pollFields !== void 0 && pollFields.length > 0) {
+ params.append("poll.fields", pollFields.join(","));
+ }
if (userFields !== void 0 && userFields.length > 0) {
params.append("user.fields", userFields.join(","));
}
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ if (placeFields !== void 0 && placeFields.length > 0) {
+ params.append("place.fields", placeFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["dm.read", "tweet.read", "users.read"]
+ BearerToken: []
+ },
+ {
+ OAuth2UserToken: ["tweet.read", "users.read"]
},
{
UserToken: []
@@ -9393,57 +9143,86 @@ var DirectMessagesClient = class {
);
}
/**
- * Get DM events for a DM conversation
- * Retrieves direct message events for a specific conversation.
+ * Search all Posts
+ * Retrieves Posts from the full archive matching a search query.
- * @param id The DM conversation ID.
+ * @param query One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getEventsByConversationId(id, options = {}) {
+ async searchAll(query, options = {}) {
const paramMappings = {
+ start_time: "startTime",
+ end_time: "endTime",
+ since_id: "sinceId",
+ until_id: "untilId",
max_results: "maxResults",
+ next_token: "nextToken",
pagination_token: "paginationToken",
- event_types: "eventTypes",
- "dm_event.fields": "dmEventFields",
+ sort_order: "sortOrder",
+ "tweet.fields": "tweetFields",
"media.fields": "mediaFields",
+ "poll.fields": "pollFields",
"user.fields": "userFields",
- "tweet.fields": "tweetFields"
+ "place.fields": "placeFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
+ startTime = void 0,
+ endTime = void 0,
+ sinceId = void 0,
+ untilId = void 0,
maxResults = void 0,
+ nextToken = void 0,
paginationToken = void 0,
- eventTypes = [],
- dmEventFields = [],
+ sortOrder = void 0,
+ tweetFields = [],
expansions = [],
mediaFields = [],
+ pollFields = [],
userFields = [],
- tweetFields = [],
+ placeFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/dm_conversations/{id}/dm_events";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/tweets/search/all";
const params = new URLSearchParams();
+ if (query !== void 0) {
+ params.append("query", String(query));
+ }
+ if (startTime !== void 0) {
+ params.append("start_time", String(startTime));
+ }
+ if (endTime !== void 0) {
+ params.append("end_time", String(endTime));
+ }
+ if (sinceId !== void 0) {
+ params.append("since_id", String(sinceId));
+ }
+ if (untilId !== void 0) {
+ params.append("until_id", String(untilId));
+ }
if (maxResults !== void 0) {
params.append("max_results", String(maxResults));
}
+ if (nextToken !== void 0) {
+ params.append("next_token", String(nextToken));
+ }
if (paginationToken !== void 0) {
params.append("pagination_token", String(paginationToken));
}
- if (eventTypes !== void 0 && eventTypes.length > 0) {
- params.append("event_types", eventTypes.join(","));
+ if (sortOrder !== void 0) {
+ params.append("sort_order", String(sortOrder));
}
- if (dmEventFields !== void 0 && dmEventFields.length > 0) {
- params.append("dm_event.fields", dmEventFields.join(","));
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
}
if (expansions !== void 0 && expansions.length > 0) {
params.append("expansions", expansions.join(","));
@@ -9451,20 +9230,20 @@ var DirectMessagesClient = class {
if (mediaFields !== void 0 && mediaFields.length > 0) {
params.append("media.fields", mediaFields.join(","));
}
+ if (pollFields !== void 0 && pollFields.length > 0) {
+ params.append("poll.fields", pollFields.join(","));
+ }
if (userFields !== void 0 && userFields.length > 0) {
params.append("user.fields", userFields.join(","));
}
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ if (placeFields !== void 0 && placeFields.length > 0) {
+ params.append("place.fields", placeFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["dm.read", "tweet.read", "users.read"]
- },
- {
- UserToken: []
+ BearerToken: []
}
],
...requestOptions
@@ -9475,92 +9254,100 @@ var DirectMessagesClient = class {
finalRequestOptions
);
}
-};
-
-// src/direct_messages/models.ts
-var models_exports3 = {};
-
-// src/community_notes/client.ts
-var CommunityNotesClient = class {
- client;
- /**
- * Creates a new community notes client instance
- *
- * @param client - The main X API client instance
- */
- constructor(client) {
- this.client = client;
- }
- /**
- * Normalize options object to handle both camelCase and original API parameter names
- * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
- */
- _normalizeOptions(options, paramMappings) {
- if (!options || typeof options !== "object") {
- return options;
- }
- const normalized = { ...options };
- for (const [originalName, camelName] of Object.entries(paramMappings)) {
- if (originalName in normalized && !(camelName in normalized)) {
- normalized[camelName] = normalized[originalName];
- delete normalized[originalName];
- }
- }
- return normalized;
- }
/**
- * Delete a Community Note
- * Deletes a community note.
+ * Get historical Post insights
+ * Retrieves historical engagement metrics for specified Posts within a defined time range.
- * @param id The community note id to delete.
+ * @param tweetIds List of PostIds for historical metrics.
- * @returns {Promise} Promise resolving to the API response
+ * @param endTime YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range.
+
+
+
+ * @param startTime YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range.
+
+
+
+ * @param granularity granularity of metrics response.
+
+
+
+ * @param requestedMetrics request metrics for historical request.
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async delete(id) {
- let path = "/2/notes/{id}";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ async getInsightsHistorical(tweetIds, endTime, startTime, granularity, requestedMetrics, options = {}) {
+ const paramMappings = {
+ "engagement.fields": "engagementFields"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
+ const {
+ engagementFields = [],
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/insights/historical";
const params = new URLSearchParams();
+ if (tweetIds !== void 0 && tweetIds.length > 0) {
+ params.append("tweet_ids", tweetIds.join(","));
+ }
+ if (endTime !== void 0) {
+ params.append("end_time", String(endTime));
+ }
+ if (startTime !== void 0) {
+ params.append("start_time", String(startTime));
+ }
+ if (granularity !== void 0) {
+ params.append("granularity", String(granularity));
+ }
+ if (requestedMetrics !== void 0 && requestedMetrics.length > 0) {
+ params.append("requested_metrics", requestedMetrics.join(","));
+ }
+ if (engagementFields !== void 0 && engagementFields.length > 0) {
+ params.append("engagement.fields", engagementFields.join(","));
+ }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["tweet.write"]
+ OAuth2UserToken: ["tweet.read"]
},
{
UserToken: []
}
- ]
- // No optional parameters, using empty request options
+ ],
+ ...requestOptions
};
return this.client.request(
- "DELETE",
+ "GET",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Search for Posts Eligible for Community Notes
- * Returns all the posts that are eligible for community notes.
+ * Get Post by ID
+ * Retrieves details of a specific Post by its ID.
+ * @param id A single Post ID.
- * @param testMode 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.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async searchEligiblePosts(testMode, options = {}) {
+ async getById(id, options = {}) {
const paramMappings = {
- pagination_token: "paginationToken",
- max_results: "maxResults",
- post_selection: "postSelection",
"tweet.fields": "tweetFields",
"media.fields": "mediaFields",
"poll.fields": "pollFields",
@@ -9572,9 +9359,6 @@ var CommunityNotesClient = class {
paramMappings
);
const {
- paginationToken = void 0,
- maxResults = void 0,
- postSelection = void 0,
tweetFields = [],
expansions = [],
mediaFields = [],
@@ -9583,20 +9367,9 @@ var CommunityNotesClient = class {
placeFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/notes/search/posts_eligible_for_notes";
+ let path = "/2/tweets/{id}";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (testMode !== void 0) {
- params.append("test_mode", String(testMode));
- }
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
- }
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (postSelection !== void 0) {
- params.append("post_selection", String(postSelection));
- }
if (tweetFields !== void 0 && tweetFields.length > 0) {
params.append("tweet.fields", tweetFields.join(","));
}
@@ -9619,7 +9392,10 @@ var CommunityNotesClient = class {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["tweet.read"]
+ BearerToken: []
+ },
+ {
+ OAuth2UserToken: ["tweet.read", "users.read"]
},
{
UserToken: []
@@ -9634,89 +9410,99 @@ var CommunityNotesClient = class {
);
}
/**
- * Evaluate a Community Note
- * Endpoint to evaluate a community note.
+ * Delete Post
+ * Deletes a specific Post by its ID, if owned by the authenticated user.
+
+ * @param id The ID of the Post to be deleted.
- * @returns {Promise} Promise resolving to the API response
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async evaluate(options = {}) {
- const normalizedOptions = options || {};
- const {
- body,
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/evaluate_note";
+ async delete(id) {
+ let path = "/2/tweets/{id}";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
const finalRequestOptions = {
- body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["tweet.write"]
+ OAuth2UserToken: ["tweet.read", "tweet.write", "users.read"]
},
{
UserToken: []
}
- ],
- ...requestOptions
+ ]
+ // No optional parameters, using empty request options
};
return this.client.request(
- "POST",
+ "DELETE",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Search for Community Notes Written
- * Returns all the community notes written by the user.
+ * Get Post analytics
+ * Retrieves analytics data for specified Posts within a defined time range.
- * @param testMode If true, return the notes the caller wrote for the test. If false, return the notes the caller wrote on the product.
+ * @param ids A comma separated list of Post IDs. Up to 100 are allowed in a single request.
- * @returns {Promise} Promise resolving to the API response
+ * @param endTime YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range.
+
+
+
+ * @param startTime YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range.
+
+
+
+ * @param granularity The granularity for the search counts results.
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async searchWritten(testMode, options = {}) {
+ async getAnalytics(ids, endTime, startTime, granularity, options = {}) {
const paramMappings = {
- pagination_token: "paginationToken",
- max_results: "maxResults",
- "note.fields": "noteFields"
+ "analytics.fields": "analyticsFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- paginationToken = void 0,
- maxResults = void 0,
- noteFields = [],
+ analyticsFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/notes/search/notes_written";
+ let path = "/2/tweets/analytics";
const params = new URLSearchParams();
- if (testMode !== void 0) {
- params.append("test_mode", String(testMode));
+ if (ids !== void 0 && ids.length > 0) {
+ params.append("ids", ids.join(","));
}
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
+ if (endTime !== void 0) {
+ params.append("end_time", String(endTime));
}
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
+ if (startTime !== void 0) {
+ params.append("start_time", String(startTime));
}
- if (noteFields !== void 0 && noteFields.length > 0) {
- params.append("note.fields", noteFields.join(","));
+ if (granularity !== void 0) {
+ params.append("granularity", String(granularity));
+ }
+ if (analyticsFields !== void 0 && analyticsFields.length > 0) {
+ params.append("analytics.fields", analyticsFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["tweet.read"]
+ OAuth2UserToken: ["tweet.read", "users.read"]
},
{
UserToken: []
@@ -9731,28 +9517,70 @@ var CommunityNotesClient = class {
);
}
/**
- * Create a Community Note
- * Creates a community note endpoint for LLM use case.
+ * Get Posts by IDs
+ * Retrieves details of multiple Posts by their IDs.
- * @returns {Promise} Promise resolving to the API response
+ * @param ids A comma separated list of Post IDs. Up to 100 are allowed in a single request.
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async create(options = {}) {
- const normalizedOptions = options || {};
+ async getByIds(ids, options = {}) {
+ const paramMappings = {
+ "tweet.fields": "tweetFields",
+ "media.fields": "mediaFields",
+ "poll.fields": "pollFields",
+ "user.fields": "userFields",
+ "place.fields": "placeFields"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
const {
- body,
+ tweetFields = [],
+ expansions = [],
+ mediaFields = [],
+ pollFields = [],
+ userFields = [],
+ placeFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/notes";
+ let path = "/2/tweets";
const params = new URLSearchParams();
+ if (ids !== void 0 && ids.length > 0) {
+ params.append("ids", ids.join(","));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (mediaFields !== void 0 && mediaFields.length > 0) {
+ params.append("media.fields", mediaFields.join(","));
+ }
+ if (pollFields !== void 0 && pollFields.length > 0) {
+ params.append("poll.fields", pollFields.join(","));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (placeFields !== void 0 && placeFields.length > 0) {
+ params.append("place.fields", placeFields.join(","));
+ }
const finalRequestOptions = {
- body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["tweet.write"]
+ BearerToken: []
+ },
+ {
+ OAuth2UserToken: ["tweet.read", "users.read"]
},
{
UserToken: []
@@ -9761,226 +9589,116 @@ var CommunityNotesClient = class {
...requestOptions
};
return this.client.request(
- "POST",
+ "GET",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
-};
-
-// src/community_notes/models.ts
-var models_exports4 = {};
-
-// src/posts/client.ts
-var PostsClient = class {
- client;
- /**
- * Creates a new posts client instance
- *
- * @param client - The main X API client instance
- */
- constructor(client) {
- this.client = client;
- }
- /**
- * Normalize options object to handle both camelCase and original API parameter names
- * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
- */
- _normalizeOptions(options, paramMappings) {
- if (!options || typeof options !== "object") {
- return options;
- }
- const normalized = { ...options };
- for (const [originalName, camelName] of Object.entries(paramMappings)) {
- if (originalName in normalized && !(camelName in normalized)) {
- normalized[camelName] = normalized[originalName];
- delete normalized[originalName];
- }
- }
- return normalized;
- }
/**
- * Hide reply
- * Hides or unhides a reply to a conversation owned by the authenticated user.
-
-
- * @param tweetId The ID of the reply that you want to hide or unhide.
+ * Create or Edit Post
+ * Creates a new Post for the authenticated user, or edits an existing Post when edit_options are provided.
+ * @param body Request body
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async hideReply(tweetId, options = {}) {
- const normalizedOptions = options || {};
- const {
- body,
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/tweets/{tweet_id}/hidden";
- path = path.replace("{tweet_id}", encodeURIComponent(String(tweetId)));
+ async create(body) {
+ let path = "/2/tweets";
const params = new URLSearchParams();
const finalRequestOptions = {
- body: body ? JSON.stringify(body) : void 0,
+ body: JSON.stringify(body || {}),
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["tweet.moderate.write", "tweet.read", "users.read"]
+ OAuth2UserToken: ["tweet.read", "tweet.write", "users.read"]
},
{
UserToken: []
}
- ],
- ...requestOptions
+ ]
+ // No optional parameters, using empty request options
};
return this.client.request(
- "PUT",
+ "POST",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get Post analytics
- * Retrieves analytics data for specified Posts within a defined time range.
-
-
-
- * @param ids A comma separated list of Post IDs. Up to 100 are allowed in a single request.
-
-
-
- * @param endTime YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range.
-
-
-
- * @param startTime YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range.
+ * Get count of recent Posts
+ * Retrieves the count of Posts from the last 7 days matching a search query.
- * @param granularity The granularity for the search counts results.
+ * @param query One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getAnalytics(ids, endTime, startTime, granularity, options = {}) {
+ async getCountsRecent(query, options = {}) {
const paramMappings = {
- "analytics.fields": "analyticsFields"
+ start_time: "startTime",
+ end_time: "endTime",
+ since_id: "sinceId",
+ until_id: "untilId",
+ next_token: "nextToken",
+ pagination_token: "paginationToken",
+ "search_count.fields": "searchCountFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- analyticsFields = [],
+ startTime = void 0,
+ endTime = void 0,
+ sinceId = void 0,
+ untilId = void 0,
+ nextToken = void 0,
+ paginationToken = void 0,
+ granularity = void 0,
+ searchCountFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/analytics";
+ let path = "/2/tweets/counts/recent";
const params = new URLSearchParams();
- if (ids !== void 0 && ids.length > 0) {
- params.append("ids", ids.join(","));
- }
- if (endTime !== void 0) {
- params.append("end_time", String(endTime));
+ if (query !== void 0) {
+ params.append("query", String(query));
}
if (startTime !== void 0) {
params.append("start_time", String(startTime));
}
- if (granularity !== void 0) {
- params.append("granularity", String(granularity));
+ if (endTime !== void 0) {
+ params.append("end_time", String(endTime));
}
- if (analyticsFields !== void 0 && analyticsFields.length > 0) {
- params.append("analytics.fields", analyticsFields.join(","));
+ if (sinceId !== void 0) {
+ params.append("since_id", String(sinceId));
}
- const finalRequestOptions = {
- // Pass security requirements for smart auth selection
- security: [
- {
- OAuth2UserToken: ["tweet.read", "users.read"]
- },
- {
- UserToken: []
- }
- ],
- ...requestOptions
- };
- return this.client.request(
- "GET",
- path + (params.toString() ? `?${params.toString()}` : ""),
- finalRequestOptions
- );
- }
- /**
- * Get historical Post insights
- * Retrieves historical engagement metrics for specified Posts within a defined time range.
-
-
-
- * @param tweetIds List of PostIds for historical metrics.
-
-
-
- * @param endTime YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range.
-
-
-
- * @param startTime YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range.
-
-
-
- * @param granularity granularity of metrics response.
-
-
-
- * @param requestedMetrics request metrics for historical request.
-
-
-
- * @returns {Promise} Promise resolving to the API response
- */
- // Overload 1: Default behavior (unwrapped response)
- async getInsightsHistorical(tweetIds, endTime, startTime, granularity, requestedMetrics, options = {}) {
- const paramMappings = {
- "engagement.fields": "engagementFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
- const {
- engagementFields = [],
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/insights/historical";
- const params = new URLSearchParams();
- if (tweetIds !== void 0 && tweetIds.length > 0) {
- params.append("tweet_ids", tweetIds.join(","));
+ if (untilId !== void 0) {
+ params.append("until_id", String(untilId));
}
- if (endTime !== void 0) {
- params.append("end_time", String(endTime));
+ if (nextToken !== void 0) {
+ params.append("next_token", String(nextToken));
}
- if (startTime !== void 0) {
- params.append("start_time", String(startTime));
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
}
if (granularity !== void 0) {
params.append("granularity", String(granularity));
}
- if (requestedMetrics !== void 0 && requestedMetrics.length > 0) {
- params.append("requested_metrics", requestedMetrics.join(","));
- }
- if (engagementFields !== void 0 && engagementFields.length > 0) {
- params.append("engagement.fields", engagementFields.join(","));
+ if (searchCountFields !== void 0 && searchCountFields.length > 0) {
+ params.append("search_count.fields", searchCountFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["tweet.read"]
- },
- {
- UserToken: []
+ BearerToken: []
}
],
...requestOptions
@@ -9992,8 +9710,8 @@ var PostsClient = class {
);
}
/**
- * Get count of recent Posts
- * Retrieves the count of Posts from the last 7 days matching a search query.
+ * Get count of all Posts
+ * Retrieves the count of Posts matching a search query from the full archive.
@@ -10001,10 +9719,10 @@ var PostsClient = class {
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getCountsRecent(query, options = {}) {
+ async getCountsAll(query, options = {}) {
const paramMappings = {
start_time: "startTime",
end_time: "endTime",
@@ -10029,7 +9747,7 @@ var PostsClient = class {
searchCountFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/counts/recent";
+ let path = "/2/tweets/counts/all";
const params = new URLSearchParams();
if (query !== void 0) {
params.append("query", String(query));
@@ -10074,8 +9792,8 @@ var PostsClient = class {
);
}
/**
- * Get count of all Posts
- * Retrieves the count of Posts matching a search query from the full archive.
+ * Search recent Posts
+ * Retrieves Posts from the last 7 days matching a search query.
@@ -10083,18 +9801,24 @@ var PostsClient = class {
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getCountsAll(query, options = {}) {
+ async searchRecent(query, options = {}) {
const paramMappings = {
start_time: "startTime",
end_time: "endTime",
since_id: "sinceId",
until_id: "untilId",
+ max_results: "maxResults",
next_token: "nextToken",
pagination_token: "paginationToken",
- "search_count.fields": "searchCountFields"
+ sort_order: "sortOrder",
+ "tweet.fields": "tweetFields",
+ "media.fields": "mediaFields",
+ "poll.fields": "pollFields",
+ "user.fields": "userFields",
+ "place.fields": "placeFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
@@ -10105,13 +9829,19 @@ var PostsClient = class {
endTime = void 0,
sinceId = void 0,
untilId = void 0,
+ maxResults = void 0,
nextToken = void 0,
paginationToken = void 0,
- granularity = void 0,
- searchCountFields = [],
+ sortOrder = void 0,
+ tweetFields = [],
+ expansions = [],
+ mediaFields = [],
+ pollFields = [],
+ userFields = [],
+ placeFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/counts/all";
+ let path = "/2/tweets/search/recent";
const params = new URLSearchParams();
if (query !== void 0) {
params.append("query", String(query));
@@ -10128,23 +9858,47 @@ var PostsClient = class {
if (untilId !== void 0) {
params.append("until_id", String(untilId));
}
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
+ }
if (nextToken !== void 0) {
params.append("next_token", String(nextToken));
}
if (paginationToken !== void 0) {
params.append("pagination_token", String(paginationToken));
}
- if (granularity !== void 0) {
- params.append("granularity", String(granularity));
+ if (sortOrder !== void 0) {
+ params.append("sort_order", String(sortOrder));
}
- if (searchCountFields !== void 0 && searchCountFields.length > 0) {
- params.append("search_count.fields", searchCountFields.join(","));
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (mediaFields !== void 0 && mediaFields.length > 0) {
+ params.append("media.fields", mediaFields.join(","));
+ }
+ if (pollFields !== void 0 && pollFields.length > 0) {
+ params.append("poll.fields", pollFields.join(","));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (placeFields !== void 0 && placeFields.length > 0) {
+ params.append("place.fields", placeFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
BearerToken: []
+ },
+ {
+ OAuth2UserToken: ["tweet.read", "users.read"]
+ },
+ {
+ UserToken: []
}
],
...requestOptions
@@ -10156,8 +9910,49 @@ var PostsClient = class {
);
}
/**
- * Get Reposts
- * Retrieves a list of Posts that repost a specific Post by its ID.
+ * Hide reply
+ * Hides or unhides a reply to a conversation owned by the authenticated user.
+
+
+ * @param tweetId The ID of the reply that you want to hide or unhide.
+
+
+
+
+ * @returns {Promise} Promise resolving to the API response
+ */
+ // Overload 1: Default behavior (unwrapped response)
+ async hideReply(tweetId, options = {}) {
+ const normalizedOptions = options || {};
+ const {
+ body,
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/tweets/{tweet_id}/hidden";
+ path = path.replace("{tweet_id}", encodeURIComponent(String(tweetId)));
+ const params = new URLSearchParams();
+ const finalRequestOptions = {
+ body: body ? JSON.stringify(body) : void 0,
+ // Pass security requirements for smart auth selection
+ security: [
+ {
+ OAuth2UserToken: ["tweet.moderate.write", "tweet.read", "users.read"]
+ },
+ {
+ UserToken: []
+ }
+ ],
+ ...requestOptions
+ };
+ return this.client.request(
+ "PUT",
+ path + (params.toString() ? `?${params.toString()}` : ""),
+ finalRequestOptions
+ );
+ }
+ /**
+ * Get Reposted by
+ * Retrieves a list of Users who reposted a specific Post by its ID.
* @param id A single Post ID.
@@ -10165,18 +9960,15 @@ var PostsClient = class {
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getReposts(id, options = {}) {
+ async getRepostedBy(id, options = {}) {
const paramMappings = {
max_results: "maxResults",
pagination_token: "paginationToken",
- "tweet.fields": "tweetFields",
- "media.fields": "mediaFields",
- "poll.fields": "pollFields",
"user.fields": "userFields",
- "place.fields": "placeFields"
+ "tweet.fields": "tweetFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
@@ -10185,15 +9977,12 @@ var PostsClient = class {
const {
maxResults = void 0,
paginationToken = void 0,
- tweetFields = [],
- expansions = [],
- mediaFields = [],
- pollFields = [],
userFields = [],
- placeFields = [],
+ expansions = [],
+ tweetFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/{id}/retweets";
+ let path = "/2/tweets/{id}/retweeted_by";
path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
if (maxResults !== void 0) {
@@ -10202,23 +9991,14 @@ var PostsClient = class {
if (paginationToken !== void 0) {
params.append("pagination_token", String(paginationToken));
}
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
}
if (expansions !== void 0 && expansions.length > 0) {
params.append("expansions", expansions.join(","));
}
- if (mediaFields !== void 0 && mediaFields.length > 0) {
- params.append("media.fields", mediaFields.join(","));
- }
- if (pollFields !== void 0 && pollFields.length > 0) {
- params.append("poll.fields", pollFields.join(","));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (placeFields !== void 0 && placeFields.length > 0) {
- params.append("place.fields", placeFields.join(","));
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
@@ -10242,8 +10022,8 @@ var PostsClient = class {
);
}
/**
- * Get Post by ID
- * Retrieves details of a specific Post by its ID.
+ * Get Quoted Posts
+ * Retrieves a list of Posts that quote a specific Post by its ID.
* @param id A single Post ID.
@@ -10251,11 +10031,13 @@ var PostsClient = class {
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getById(id, options = {}) {
+ async getQuoted(id, options = {}) {
const paramMappings = {
+ max_results: "maxResults",
+ pagination_token: "paginationToken",
"tweet.fields": "tweetFields",
"media.fields": "mediaFields",
"poll.fields": "pollFields",
@@ -10267,6 +10049,9 @@ var PostsClient = class {
paramMappings
);
const {
+ maxResults = void 0,
+ paginationToken = void 0,
+ exclude = [],
tweetFields = [],
expansions = [],
mediaFields = [],
@@ -10275,9 +10060,18 @@ var PostsClient = class {
placeFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/{id}";
+ let path = "/2/tweets/{id}/quote_tweets";
path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
+ }
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
+ }
+ if (exclude !== void 0 && exclude.length > 0) {
+ params.append("exclude", exclude.join(","));
+ }
if (tweetFields !== void 0 && tweetFields.length > 0) {
params.append("tweet.fields", tweetFields.join(","));
}
@@ -10318,54 +10112,120 @@ var PostsClient = class {
);
}
/**
- * Delete Post
- * Deletes a specific Post by its ID, if owned by the authenticated user.
+ * Get Liking Users
+ * Retrieves a list of Users who liked a specific Post by its ID.
- * @param id The ID of the Post to be deleted.
+ * @param id A single Post ID.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async delete(id) {
- let path = "/2/tweets/{id}";
+ async getLikingUsers(id, options = {}) {
+ const paramMappings = {
+ max_results: "maxResults",
+ pagination_token: "paginationToken",
+ "user.fields": "userFields",
+ "tweet.fields": "tweetFields"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
+ const {
+ maxResults = void 0,
+ paginationToken = void 0,
+ userFields = [],
+ expansions = [],
+ tweetFields = [],
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/tweets/{id}/liking_users";
path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
+ }
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["tweet.read", "tweet.write", "users.read"]
+ OAuth2UserToken: ["like.read", "tweet.read", "users.read"]
},
{
UserToken: []
}
- ]
- // No optional parameters, using empty request options
+ ],
+ ...requestOptions
};
return this.client.request(
- "DELETE",
+ "GET",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
+};
+
+// src/posts/models.ts
+var models_exports9 = {};
+
+// src/lists/client.ts
+var ListsClient = class {
+ client;
+ /**
+ * Creates a new lists client instance
+ *
+ * @param client - The main X API client instance
+ */
+ constructor(client) {
+ this.client = client;
+ }
/**
- * Get Reposted by
- * Retrieves a list of Users who reposted a specific Post by its ID.
+ * Normalize options object to handle both camelCase and original API parameter names
+ * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
+ */
+ _normalizeOptions(options, paramMappings) {
+ if (!options || typeof options !== "object") {
+ return options;
+ }
+ const normalized = { ...options };
+ for (const [originalName, camelName] of Object.entries(paramMappings)) {
+ if (originalName in normalized && !(camelName in normalized)) {
+ normalized[camelName] = normalized[originalName];
+ delete normalized[originalName];
+ }
+ }
+ return normalized;
+ }
+ /**
+ * Get List members
+ * Retrieves a list of Users who are members of a specific List by its ID.
- * @param id A single Post ID.
+ * @param id The ID of the List.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getRepostedBy(id, options = {}) {
+ async getMembers(id, options = {}) {
const paramMappings = {
max_results: "maxResults",
pagination_token: "paginationToken",
@@ -10384,7 +10244,7 @@ var PostsClient = class {
tweetFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/{id}/retweeted_by";
+ let path = "/2/lists/{id}/members";
path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
if (maxResults !== void 0) {
@@ -10409,7 +10269,7 @@ var PostsClient = class {
BearerToken: []
},
{
- OAuth2UserToken: ["tweet.read", "users.read"]
+ OAuth2UserToken: ["list.read", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -10424,57 +10284,104 @@ var PostsClient = class {
);
}
/**
- * Get 28-hour Post insights
- * Retrieves engagement metrics for specified Posts over the last 28 hours.
+ * Add List member
+ * Adds a User to a specific List by its ID.
+ * @param id The ID of the List for which to add a member.
- * @param tweetIds List of PostIds for 28hr metrics.
- * @param granularity granularity of metrics response.
+ * @returns {Promise} Promise resolving to the API response
+ */
+ // Overload 1: Default behavior (unwrapped response)
+ async addMember(id, options = {}) {
+ const normalizedOptions = options || {};
+ const {
+ body,
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/lists/{id}/members";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
+ const params = new URLSearchParams();
+ const finalRequestOptions = {
+ body: body ? JSON.stringify(body) : void 0,
+ // Pass security requirements for smart auth selection
+ security: [
+ {
+ OAuth2UserToken: ["list.write", "tweet.read", "users.read"]
+ },
+ {
+ UserToken: []
+ }
+ ],
+ ...requestOptions
+ };
+ return this.client.request(
+ "POST",
+ path + (params.toString() ? `?${params.toString()}` : ""),
+ finalRequestOptions
+ );
+ }
+ /**
+ * Get List followers
+ * Retrieves a list of Users who follow a specific List by its ID.
+ * @param id The ID of the List.
- * @param requestedMetrics request metrics for historical request.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getInsights28hr(tweetIds, granularity, requestedMetrics, options = {}) {
+ async getFollowers(id, options = {}) {
const paramMappings = {
- "engagement.fields": "engagementFields"
+ max_results: "maxResults",
+ pagination_token: "paginationToken",
+ "user.fields": "userFields",
+ "tweet.fields": "tweetFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- engagementFields = [],
+ maxResults = void 0,
+ paginationToken = void 0,
+ userFields = [],
+ expansions = [],
+ tweetFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/insights/28hr";
+ let path = "/2/lists/{id}/followers";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (tweetIds !== void 0 && tweetIds.length > 0) {
- params.append("tweet_ids", tweetIds.join(","));
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
}
- if (granularity !== void 0) {
- params.append("granularity", String(granularity));
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
}
- if (requestedMetrics !== void 0 && requestedMetrics.length > 0) {
- params.append("requested_metrics", requestedMetrics.join(","));
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
}
- if (engagementFields !== void 0 && engagementFields.length > 0) {
- params.append("engagement.fields", engagementFields.join(","));
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["tweet.read"]
+ BearerToken: []
+ },
+ {
+ OAuth2UserToken: ["list.read", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -10489,20 +10396,22 @@ var PostsClient = class {
);
}
/**
- * Get Posts by IDs
- * Retrieves details of multiple Posts by their IDs.
+ * Get List Posts
+ * Retrieves a list of Posts associated with a specific List by its ID.
+ * @param id The ID of the List.
- * @param ids A comma separated list of Post IDs. Up to 100 are allowed in a single request.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getByIds(ids, options = {}) {
+ async getPosts(id, options = {}) {
const paramMappings = {
+ max_results: "maxResults",
+ pagination_token: "paginationToken",
"tweet.fields": "tweetFields",
"media.fields": "mediaFields",
"poll.fields": "pollFields",
@@ -10514,6 +10423,8 @@ var PostsClient = class {
paramMappings
);
const {
+ maxResults = void 0,
+ paginationToken = void 0,
tweetFields = [],
expansions = [],
mediaFields = [],
@@ -10522,10 +10433,14 @@ var PostsClient = class {
placeFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets";
+ let path = "/2/lists/{id}/tweets";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (ids !== void 0 && ids.length > 0) {
- params.append("ids", ids.join(","));
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
+ }
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
}
if (tweetFields !== void 0 && tweetFields.length > 0) {
params.append("tweet.fields", tweetFields.join(","));
@@ -10552,7 +10467,7 @@ var PostsClient = class {
BearerToken: []
},
{
- OAuth2UserToken: ["tweet.read", "users.read"]
+ OAuth2UserToken: ["list.read", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -10567,25 +10482,32 @@ var PostsClient = class {
);
}
/**
- * Create or Edit Post
- * Creates a new Post for the authenticated user, or edits an existing Post when edit_options are provided.
+ * Remove List member
+ * Removes a User from a specific List by its ID and the User’s ID.
+ * @param id The ID of the List to remove a member.
- * @param body Request body
- * @returns {Promise} Promise resolving to the API response
+
+ * @param userId The ID of User that will be removed from the List.
+
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async create(body) {
- let path = "/2/tweets";
+ async removeMemberByUserId(id, userId) {
+ let path = "/2/lists/{id}/members/{user_id}";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
+ path = path.replace("{user_id}", encodeURIComponent(String(userId)));
const params = new URLSearchParams();
const finalRequestOptions = {
- body: JSON.stringify(body || {}),
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["tweet.read", "tweet.write", "users.read"]
+ OAuth2UserToken: ["list.write", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -10594,66 +10516,59 @@ var PostsClient = class {
// No optional parameters, using empty request options
};
return this.client.request(
- "POST",
+ "DELETE",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get Liking Users
- * Retrieves a list of Users who liked a specific Post by its ID.
+ * Get List by ID
+ * Retrieves details of a specific List by its ID.
- * @param id A single Post ID.
+ * @param id The ID of the List.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getLikingUsers(id, options = {}) {
+ async getById(id, options = {}) {
const paramMappings = {
- max_results: "maxResults",
- pagination_token: "paginationToken",
- "user.fields": "userFields",
- "tweet.fields": "tweetFields"
+ "list.fields": "listFields",
+ "user.fields": "userFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- maxResults = void 0,
- paginationToken = void 0,
- userFields = [],
+ listFields = [],
expansions = [],
- tweetFields = [],
+ userFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/{id}/liking_users";
+ let path = "/2/lists/{id}";
path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
+ if (listFields !== void 0 && listFields.length > 0) {
+ params.append("list.fields", listFields.join(","));
}
if (expansions !== void 0 && expansions.length > 0) {
params.append("expansions", expansions.join(","));
}
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["like.read", "tweet.read", "users.read"]
+ BearerToken: []
+ },
+ {
+ OAuth2UserToken: ["list.read", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -10668,312 +10583,109 @@ var PostsClient = class {
);
}
/**
- * Search all Posts
- * Retrieves Posts from the full archive matching a search query.
+ * Update List
+ * Updates the details of a specific List owned by the authenticated user by its ID.
+ * @param id The ID of the List to modify.
- * @param query One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async searchAll(query, options = {}) {
- const paramMappings = {
- start_time: "startTime",
- end_time: "endTime",
- since_id: "sinceId",
- until_id: "untilId",
- max_results: "maxResults",
- next_token: "nextToken",
- pagination_token: "paginationToken",
- sort_order: "sortOrder",
- "tweet.fields": "tweetFields",
- "media.fields": "mediaFields",
- "poll.fields": "pollFields",
- "user.fields": "userFields",
- "place.fields": "placeFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
+ async update(id, options = {}) {
+ const normalizedOptions = options || {};
const {
- startTime = void 0,
- endTime = void 0,
- sinceId = void 0,
- untilId = void 0,
- maxResults = void 0,
- nextToken = void 0,
- paginationToken = void 0,
- sortOrder = void 0,
- tweetFields = [],
- expansions = [],
- mediaFields = [],
- pollFields = [],
- userFields = [],
- placeFields = [],
+ body,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/search/all";
+ let path = "/2/lists/{id}";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (query !== void 0) {
- params.append("query", String(query));
- }
- if (startTime !== void 0) {
- params.append("start_time", String(startTime));
- }
- if (endTime !== void 0) {
- params.append("end_time", String(endTime));
- }
- if (sinceId !== void 0) {
- params.append("since_id", String(sinceId));
- }
- if (untilId !== void 0) {
- params.append("until_id", String(untilId));
- }
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (nextToken !== void 0) {
- params.append("next_token", String(nextToken));
- }
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
- }
- if (sortOrder !== void 0) {
- params.append("sort_order", String(sortOrder));
- }
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (mediaFields !== void 0 && mediaFields.length > 0) {
- params.append("media.fields", mediaFields.join(","));
- }
- if (pollFields !== void 0 && pollFields.length > 0) {
- params.append("poll.fields", pollFields.join(","));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (placeFields !== void 0 && placeFields.length > 0) {
- params.append("place.fields", placeFields.join(","));
- }
const finalRequestOptions = {
+ body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
+ OAuth2UserToken: ["list.write", "tweet.read", "users.read"]
+ },
+ {
+ UserToken: []
}
],
...requestOptions
};
return this.client.request(
- "GET",
+ "PUT",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get Quoted Posts
- * Retrieves a list of Posts that quote a specific Post by its ID.
+ * Delete List
+ * Deletes a specific List owned by the authenticated user by its ID.
- * @param id A single Post ID.
+ * @param id The ID of the List to delete.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getQuoted(id, options = {}) {
- const paramMappings = {
- max_results: "maxResults",
- pagination_token: "paginationToken",
- "tweet.fields": "tweetFields",
- "media.fields": "mediaFields",
- "poll.fields": "pollFields",
- "user.fields": "userFields",
- "place.fields": "placeFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
- const {
- maxResults = void 0,
- paginationToken = void 0,
- exclude = [],
- tweetFields = [],
- expansions = [],
- mediaFields = [],
- pollFields = [],
- userFields = [],
- placeFields = [],
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/tweets/{id}/quote_tweets";
+ async delete(id) {
+ let path = "/2/lists/{id}";
path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
- }
- if (exclude !== void 0 && exclude.length > 0) {
- params.append("exclude", exclude.join(","));
- }
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (mediaFields !== void 0 && mediaFields.length > 0) {
- params.append("media.fields", mediaFields.join(","));
- }
- if (pollFields !== void 0 && pollFields.length > 0) {
- params.append("poll.fields", pollFields.join(","));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (placeFields !== void 0 && placeFields.length > 0) {
- params.append("place.fields", placeFields.join(","));
- }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
- },
- {
- OAuth2UserToken: ["tweet.read", "users.read"]
+ OAuth2UserToken: ["list.write", "tweet.read", "users.read"]
},
{
UserToken: []
}
- ],
- ...requestOptions
+ ]
+ // No optional parameters, using empty request options
};
return this.client.request(
- "GET",
+ "DELETE",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Search recent Posts
- * Retrieves Posts from the last 7 days matching a search query.
-
-
-
- * @param query One query/rule/filter for matching Posts. Refer to https://t.co/rulelength to identify the max query length.
+ * Create List
+ * Creates a new List for the authenticated user.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async searchRecent(query, options = {}) {
- const paramMappings = {
- start_time: "startTime",
- end_time: "endTime",
- since_id: "sinceId",
- until_id: "untilId",
- max_results: "maxResults",
- next_token: "nextToken",
- pagination_token: "paginationToken",
- sort_order: "sortOrder",
- "tweet.fields": "tweetFields",
- "media.fields": "mediaFields",
- "poll.fields": "pollFields",
- "user.fields": "userFields",
- "place.fields": "placeFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
+ async create(options = {}) {
+ const normalizedOptions = options || {};
const {
- startTime = void 0,
- endTime = void 0,
- sinceId = void 0,
- untilId = void 0,
- maxResults = void 0,
- nextToken = void 0,
- paginationToken = void 0,
- sortOrder = void 0,
- tweetFields = [],
- expansions = [],
- mediaFields = [],
- pollFields = [],
- userFields = [],
- placeFields = [],
+ body,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/search/recent";
+ let path = "/2/lists";
const params = new URLSearchParams();
- if (query !== void 0) {
- params.append("query", String(query));
- }
- if (startTime !== void 0) {
- params.append("start_time", String(startTime));
- }
- if (endTime !== void 0) {
- params.append("end_time", String(endTime));
- }
- if (sinceId !== void 0) {
- params.append("since_id", String(sinceId));
- }
- if (untilId !== void 0) {
- params.append("until_id", String(untilId));
- }
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (nextToken !== void 0) {
- params.append("next_token", String(nextToken));
- }
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
- }
- if (sortOrder !== void 0) {
- params.append("sort_order", String(sortOrder));
- }
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (mediaFields !== void 0 && mediaFields.length > 0) {
- params.append("media.fields", mediaFields.join(","));
- }
- if (pollFields !== void 0 && pollFields.length > 0) {
- params.append("poll.fields", pollFields.join(","));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (placeFields !== void 0 && placeFields.length > 0) {
- params.append("place.fields", placeFields.join(","));
- }
const finalRequestOptions = {
+ body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
- },
- {
- OAuth2UserToken: ["tweet.read", "users.read"]
+ OAuth2UserToken: [
+ "list.read",
+ "list.write",
+ "tweet.read",
+ "users.read"
+ ]
},
{
UserToken: []
@@ -10982,21 +10694,21 @@ var PostsClient = class {
...requestOptions
};
return this.client.request(
- "GET",
+ "POST",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
};
-// src/posts/models.ts
-var models_exports5 = {};
+// src/lists/models.ts
+var models_exports10 = {};
-// src/trends/client.ts
-var TrendsClient = class {
+// src/community_notes/client.ts
+var CommunityNotesClient = class {
client;
/**
- * Creates a new trends client instance
+ * Creates a new community notes client instance
*
* @param client - The main X API client instance
*/
@@ -11021,136 +10733,124 @@ var TrendsClient = class {
return normalized;
}
/**
- * Get AI Trends by ID
- * Retrieves an AI trend by its ID.
+ * Delete a Community Note
+ * Deletes a community note.
- * @param id The ID of the ai trend.
+ * @param id The community note id to delete.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getAi(id, options = {}) {
- const paramMappings = {
- "news.fields": "newsFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
- const {
- newsFields = [],
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/ai_trends/{id}";
+ async delete(id) {
+ let path = "/2/notes/{id}";
path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (newsFields !== void 0 && newsFields.length > 0) {
- params.append("news.fields", newsFields.join(","));
- }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
+ OAuth2UserToken: ["tweet.write"]
+ },
+ {
+ UserToken: []
}
- ],
- ...requestOptions
+ ]
+ // No optional parameters, using empty request options
};
return this.client.request(
- "GET",
+ "DELETE",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get Trends by WOEID
- * Retrieves trending topics for a specific location identified by its WOEID.
-
-
- * @param woeid The WOEID of the place to lookup a trend for.
-
+ * Evaluate a Community Note
+ * Endpoint to evaluate a community note.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getByWoeid(woeid, options = {}) {
- const paramMappings = {
- max_trends: "maxTrends",
- "trend.fields": "trendFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
+ async evaluate(options = {}) {
+ const normalizedOptions = options || {};
const {
- maxTrends = void 0,
- trendFields = [],
+ body,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/trends/by/woeid/{woeid}";
- path = path.replace("{woeid}", encodeURIComponent(String(woeid)));
+ let path = "/2/evaluate_note";
const params = new URLSearchParams();
- if (maxTrends !== void 0) {
- params.append("max_trends", String(maxTrends));
- }
- if (trendFields !== void 0 && trendFields.length > 0) {
- params.append("trend.fields", trendFields.join(","));
- }
const finalRequestOptions = {
+ body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
+ OAuth2UserToken: ["tweet.write"]
+ },
+ {
+ UserToken: []
}
],
...requestOptions
};
return this.client.request(
- "GET",
+ "POST",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get personalized Trends
- * Retrieves personalized trending topics for the authenticated user.
+ * Search for Community Notes Written
+ * Returns all the community notes written by the user.
- * @returns {Promise} Promise resolving to the API response
+ * @param testMode If true, return the notes the caller wrote for the test. If false, return the notes the caller wrote on the product.
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getPersonalized(options = {}) {
+ async searchWritten(testMode, options = {}) {
const paramMappings = {
- "personalized_trend.fields": "personalizedTrendFields"
+ pagination_token: "paginationToken",
+ max_results: "maxResults",
+ "note.fields": "noteFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- personalizedTrendFields = [],
+ paginationToken = void 0,
+ maxResults = void 0,
+ noteFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/personalized_trends";
+ let path = "/2/notes/search/notes_written";
const params = new URLSearchParams();
- if (personalizedTrendFields !== void 0 && personalizedTrendFields.length > 0) {
- params.append(
- "personalized_trend.fields",
- personalizedTrendFields.join(",")
- );
+ if (testMode !== void 0) {
+ params.append("test_mode", String(testMode));
+ }
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
+ }
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
+ }
+ if (noteFields !== void 0 && noteFields.length > 0) {
+ params.append("note.fields", noteFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["tweet.read", "users.read"]
+ OAuth2UserToken: ["tweet.read"]
},
{
UserToken: []
@@ -11164,216 +10864,122 @@ var TrendsClient = class {
finalRequestOptions
);
}
-};
-
-// src/trends/models.ts
-var models_exports6 = {};
-
-// src/activity/client.ts
-var ActivityClient = class {
- client;
- /**
- * Creates a new activity client instance
- *
- * @param client - The main X API client instance
- */
- constructor(client) {
- this.client = client;
- }
- /**
- * Normalize options object to handle both camelCase and original API parameter names
- * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
- */
- _normalizeOptions(options, paramMappings) {
- if (!options || typeof options !== "object") {
- return options;
- }
- const normalized = { ...options };
- for (const [originalName, camelName] of Object.entries(paramMappings)) {
- if (originalName in normalized && !(camelName in normalized)) {
- normalized[camelName] = normalized[originalName];
- delete normalized[originalName];
- }
- }
- return normalized;
- }
/**
- * Get X activity subscriptions
- * Get a list of active subscriptions for XAA
+ * Create a Community Note
+ * Creates a community note endpoint for LLM use case.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getSubscriptions() {
- let path = "/2/activity/subscriptions";
+ async create(options = {}) {
+ const normalizedOptions = options || {};
+ const {
+ body,
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/notes";
const params = new URLSearchParams();
const finalRequestOptions = {
+ body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
+ OAuth2UserToken: ["tweet.write"]
+ },
+ {
+ UserToken: []
}
- ]
- // No optional parameters, using empty request options
+ ],
+ ...requestOptions
};
return this.client.request(
- "GET",
+ "POST",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Create X activity subscription
- * Creates a subscription for an X activity event
+ * Search for Posts Eligible for Community Notes
+ * Returns all the posts that are eligible for community notes.
- * @returns {Promise} Promise resolving to the API response
- */
- // Overload 1: Default behavior (unwrapped response)
- async createSubscription(options = {}) {
- const normalizedOptions = options || {};
- const {
- body,
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/activity/subscriptions";
- const params = new URLSearchParams();
- const finalRequestOptions = {
- body: body ? JSON.stringify(body) : void 0,
- // Pass security requirements for smart auth selection
- security: [
- {
- BearerToken: []
- }
- ],
- ...requestOptions
- };
- return this.client.request(
- "POST",
- path + (params.toString() ? `?${params.toString()}` : ""),
- finalRequestOptions
- );
- }
- /**
- * Update X activity subscription
- * Updates a subscription for an X activity event
-
-
- * @param subscriptionId The ID of the subscription to update.
-
-
-
-
- * @returns {Promise} Promise resolving to the API response
- */
- // Overload 1: Default behavior (unwrapped response)
- async updateSubscription(subscriptionId, options = {}) {
- const normalizedOptions = options || {};
- const {
- body,
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/activity/subscriptions/{subscription_id}";
- path = path.replace(
- "{subscription_id}",
- encodeURIComponent(String(subscriptionId))
- );
- const params = new URLSearchParams();
- const finalRequestOptions = {
- body: body ? JSON.stringify(body) : void 0,
- // Pass security requirements for smart auth selection
- security: [
- {
- BearerToken: []
- }
- ],
- ...requestOptions
- };
- return this.client.request(
- "PUT",
- path + (params.toString() ? `?${params.toString()}` : ""),
- finalRequestOptions
- );
- }
- /**
- * Deletes X activity subscription
- * Deletes a subscription for an X activity event
-
-
- * @param subscriptionId The ID of the subscription to delete.
-
-
-
-
- * @returns {Promise} Promise resolving to the API response
- */
- // Overload 1: Default behavior (unwrapped response)
- async deleteSubscription(subscriptionId) {
- let path = "/2/activity/subscriptions/{subscription_id}";
- path = path.replace(
- "{subscription_id}",
- encodeURIComponent(String(subscriptionId))
- );
- const params = new URLSearchParams();
- const finalRequestOptions = {
- // Pass security requirements for smart auth selection
- security: [
- {
- BearerToken: []
- }
- ]
- // No optional parameters, using empty request options
- };
- return this.client.request(
- "DELETE",
- path + (params.toString() ? `?${params.toString()}` : ""),
- finalRequestOptions
- );
- }
- /**
- * Activity Stream
- * Stream of X Activities
+ * @param testMode 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.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async stream(options = {}) {
+ async searchEligiblePosts(testMode, options = {}) {
const paramMappings = {
- backfill_minutes: "backfillMinutes",
- start_time: "startTime",
- end_time: "endTime"
+ pagination_token: "paginationToken",
+ max_results: "maxResults",
+ post_selection: "postSelection",
+ "tweet.fields": "tweetFields",
+ "media.fields": "mediaFields",
+ "poll.fields": "pollFields",
+ "user.fields": "userFields",
+ "place.fields": "placeFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- backfillMinutes = void 0,
- startTime = void 0,
- endTime = void 0,
+ paginationToken = void 0,
+ maxResults = void 0,
+ postSelection = void 0,
+ tweetFields = [],
+ expansions = [],
+ mediaFields = [],
+ pollFields = [],
+ userFields = [],
+ placeFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/activity/stream";
+ let path = "/2/notes/search/posts_eligible_for_notes";
const params = new URLSearchParams();
- if (backfillMinutes !== void 0) {
- params.append("backfill_minutes", String(backfillMinutes));
+ if (testMode !== void 0) {
+ params.append("test_mode", String(testMode));
}
- if (startTime !== void 0) {
- params.append("start_time", String(startTime));
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
}
- if (endTime !== void 0) {
- params.append("end_time", String(endTime));
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
+ }
+ if (postSelection !== void 0) {
+ params.append("post_selection", String(postSelection));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (mediaFields !== void 0 && mediaFields.length > 0) {
+ params.append("media.fields", mediaFields.join(","));
+ }
+ if (pollFields !== void 0 && pollFields.length > 0) {
+ params.append("poll.fields", pollFields.join(","));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (placeFields !== void 0 && placeFields.length > 0) {
+ params.append("place.fields", placeFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
+ OAuth2UserToken: ["tweet.read"]
+ },
+ {
+ UserToken: []
}
],
...requestOptions
@@ -11386,14 +10992,14 @@ var ActivityClient = class {
}
};
-// src/activity/models.ts
-var models_exports7 = {};
+// src/community_notes/models.ts
+var models_exports11 = {};
-// src/usage/client.ts
-var UsageClient = class {
+// src/general/client.ts
+var GeneralClient = class {
client;
/**
- * Creates a new usage client instance
+ * Creates a new general client instance
*
* @param client - The main X API client instance
*/
@@ -11418,43 +11024,19 @@ var UsageClient = class {
return normalized;
}
/**
- * Get usage
- * Retrieves usage statistics for Posts over a specified number of days.
+ * Get OpenAPI Spec.
+ * Retrieves the full OpenAPI Specification in JSON format. (See https://github.com/OAI/OpenAPI-Specification/blob/master/README.md)
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async get(options = {}) {
- const paramMappings = {
- "usage.fields": "usageFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
- const {
- days = void 0,
- usageFields = [],
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/usage/tweets";
+ async getOpenApiSpec() {
+ let path = "/2/openapi.json";
const params = new URLSearchParams();
- if (days !== void 0) {
- params.append("days", String(days));
- }
- if (usageFields !== void 0 && usageFields.length > 0) {
- params.append("usage.fields", usageFields.join(","));
- }
const finalRequestOptions = {
- // Pass security requirements for smart auth selection
- security: [
- {
- BearerToken: []
- }
- ],
- ...requestOptions
+ // No optional parameters, using empty request options
};
return this.client.request(
"GET",
@@ -11464,14 +11046,14 @@ var UsageClient = class {
}
};
-// src/usage/models.ts
-var models_exports8 = {};
+// src/general/models.ts
+var models_exports12 = {};
-// src/spaces/client.ts
-var SpacesClient = class {
+// src/webhooks/client.ts
+var WebhooksClient = class {
client;
/**
- * Creates a new spaces client instance
+ * Creates a new webhooks client instance
*
* @param client - The main X API client instance
*/
@@ -11496,73 +11078,36 @@ var SpacesClient = class {
return normalized;
}
/**
- * Get Space Posts
- * Retrieves a list of Posts shared in a specific Space by its ID.
-
-
- * @param id The ID of the Space to be retrieved.
-
+ * Get webhook
+ * Get a list of webhook configs associated with a client app.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getPosts(id, options = {}) {
+ async get(options = {}) {
const paramMappings = {
- max_results: "maxResults",
- "tweet.fields": "tweetFields",
- "media.fields": "mediaFields",
- "poll.fields": "pollFields",
- "user.fields": "userFields",
- "place.fields": "placeFields"
+ "webhook_config.fields": "webhookConfigFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- maxResults = void 0,
- tweetFields = [],
- expansions = [],
- mediaFields = [],
- pollFields = [],
- userFields = [],
- placeFields = [],
+ webhookConfigFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/spaces/{id}/tweets";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/webhooks";
const params = new URLSearchParams();
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (mediaFields !== void 0 && mediaFields.length > 0) {
- params.append("media.fields", mediaFields.join(","));
- }
- if (pollFields !== void 0 && pollFields.length > 0) {
- params.append("poll.fields", pollFields.join(","));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (placeFields !== void 0 && placeFields.length > 0) {
- params.append("place.fields", placeFields.join(","));
+ if (webhookConfigFields !== void 0 && webhookConfigFields.length > 0) {
+ params.append("webhook_config.fields", webhookConfigFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
BearerToken: []
- },
- {
- OAuth2UserToken: ["space.read", "tweet.read", "users.read"]
}
],
...requestOptions
@@ -11574,124 +11119,58 @@ var SpacesClient = class {
);
}
/**
- * Search Spaces
- * Retrieves a list of Spaces matching the specified search query.
-
-
-
- * @param query The search query.
+ * Create webhook
+ * Creates a new webhook configuration.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async search(query, options = {}) {
- const paramMappings = {
- max_results: "maxResults",
- "space.fields": "spaceFields",
- "user.fields": "userFields",
- "topic.fields": "topicFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
+ async create(options = {}) {
+ const normalizedOptions = options || {};
const {
- state = void 0,
- maxResults = void 0,
- spaceFields = [],
- expansions = [],
- userFields = [],
- topicFields = [],
+ body,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/spaces/search";
+ let path = "/2/webhooks";
const params = new URLSearchParams();
- if (query !== void 0) {
- params.append("query", String(query));
- }
- if (state !== void 0) {
- params.append("state", String(state));
- }
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (spaceFields !== void 0 && spaceFields.length > 0) {
- params.append("space.fields", spaceFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (topicFields !== void 0 && topicFields.length > 0) {
- params.append("topic.fields", topicFields.join(","));
- }
const finalRequestOptions = {
+ body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
BearerToken: []
},
{
- OAuth2UserToken: ["space.read", "tweet.read", "users.read"]
+ UserToken: []
}
],
...requestOptions
};
return this.client.request(
- "GET",
+ "POST",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get space by ID
- * Retrieves details of a specific space by its ID.
+ * Validate webhook
+ * Triggers a CRC check for a given webhook.
- * @param id The ID of the Space to be retrieved.
+ * @param webhookId The ID of the webhook to check.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getById(id, options = {}) {
- const paramMappings = {
- "space.fields": "spaceFields",
- "user.fields": "userFields",
- "topic.fields": "topicFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
- const {
- spaceFields = [],
- expansions = [],
- userFields = [],
- topicFields = [],
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/spaces/{id}";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ async validate(webhookId) {
+ let path = "/2/webhooks/{webhook_id}";
+ path = path.replace("{webhook_id}", encodeURIComponent(String(webhookId)));
const params = new URLSearchParams();
- if (spaceFields !== void 0 && spaceFields.length > 0) {
- params.append("space.fields", spaceFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (topicFields !== void 0 && topicFields.length > 0) {
- params.append("topic.fields", topicFields.join(","));
- }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
@@ -11699,64 +11178,34 @@ var SpacesClient = class {
BearerToken: []
},
{
- OAuth2UserToken: ["space.read", "tweet.read", "users.read"]
+ UserToken: []
}
- ],
- ...requestOptions
+ ]
+ // No optional parameters, using empty request options
};
return this.client.request(
- "GET",
+ "PUT",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get Spaces by creator IDs
- * Retrieves details of Spaces created by specified User IDs.
+ * Delete webhook
+ * Deletes an existing webhook configuration.
+ * @param webhookId The ID of the webhook to delete.
- * @param userIds The IDs of Users to search through.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getByCreatorIds(userIds, options = {}) {
- const paramMappings = {
- "space.fields": "spaceFields",
- "user.fields": "userFields",
- "topic.fields": "topicFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
- const {
- spaceFields = [],
- expansions = [],
- userFields = [],
- topicFields = [],
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/spaces/by/creator_ids";
+ async delete(webhookId) {
+ let path = "/2/webhooks/{webhook_id}";
+ path = path.replace("{webhook_id}", encodeURIComponent(String(webhookId)));
const params = new URLSearchParams();
- if (userIds !== void 0 && userIds.length > 0) {
- params.append("user_ids", userIds.join(","));
- }
- if (spaceFields !== void 0 && spaceFields.length > 0) {
- params.append("space.fields", spaceFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (topicFields !== void 0 && topicFields.length > 0) {
- params.append("topic.fields", topicFields.join(","));
- }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
@@ -11764,140 +11213,139 @@ var SpacesClient = class {
BearerToken: []
},
{
- OAuth2UserToken: ["space.read", "tweet.read", "users.read"]
+ UserToken: []
}
- ],
- ...requestOptions
+ ]
+ // No optional parameters, using empty request options
};
return this.client.request(
- "GET",
+ "DELETE",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get Space ticket buyers
- * Retrieves a list of Users who purchased tickets to a specific Space by its ID.
+ * Create stream link
+ * Creates a link to deliver FilteredStream events to the given webhook.
- * @param id The ID of the Space to be retrieved.
+ * @param webhookId The webhook ID to link to your FilteredStream ruleset.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getBuyers(id, options = {}) {
+ async createStreamLink(webhookId, options = {}) {
const paramMappings = {
- pagination_token: "paginationToken",
- max_results: "maxResults",
+ "tweet.fields": "tweetFields",
+ "media.fields": "mediaFields",
+ "poll.fields": "pollFields",
"user.fields": "userFields",
- "tweet.fields": "tweetFields"
+ "place.fields": "placeFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- paginationToken = void 0,
- maxResults = void 0,
- userFields = [],
- expansions = [],
- tweetFields = [],
+ tweetFields = void 0,
+ expansions = void 0,
+ mediaFields = void 0,
+ pollFields = void 0,
+ userFields = void 0,
+ placeFields = void 0,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/spaces/{id}/buyers";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/tweets/search/webhooks/{webhook_id}";
+ path = path.replace("{webhook_id}", encodeURIComponent(String(webhookId)));
const params = new URLSearchParams();
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
+ if (tweetFields !== void 0) {
+ params.append("tweet.fields", String(tweetFields));
}
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
+ if (expansions !== void 0) {
+ params.append("expansions", String(expansions));
}
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
+ if (mediaFields !== void 0) {
+ params.append("media.fields", String(mediaFields));
}
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
+ if (pollFields !== void 0) {
+ params.append("poll.fields", String(pollFields));
}
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ if (userFields !== void 0) {
+ params.append("user.fields", String(userFields));
+ }
+ if (placeFields !== void 0) {
+ params.append("place.fields", String(placeFields));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["space.read", "tweet.read", "users.read"]
+ BearerToken: []
}
],
...requestOptions
};
return this.client.request(
- "GET",
+ "POST",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get Spaces by IDs
- * Retrieves details of multiple Spaces by their IDs.
+ * Delete stream link
+ * Deletes a link from FilteredStream events to the given webhook.
+ * @param webhookId The webhook ID to link to your FilteredStream ruleset.
- * @param ids The list of Space IDs to return.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getByIds(ids, options = {}) {
- const paramMappings = {
- "space.fields": "spaceFields",
- "user.fields": "userFields",
- "topic.fields": "topicFields"
+ async deleteStreamLink(webhookId) {
+ let path = "/2/tweets/search/webhooks/{webhook_id}";
+ path = path.replace("{webhook_id}", encodeURIComponent(String(webhookId)));
+ const params = new URLSearchParams();
+ const finalRequestOptions = {
+ // Pass security requirements for smart auth selection
+ security: [
+ {
+ BearerToken: []
+ }
+ ]
+ // No optional parameters, using empty request options
};
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
+ return this.client.request(
+ "DELETE",
+ path + (params.toString() ? `?${params.toString()}` : ""),
+ finalRequestOptions
);
- const {
- spaceFields = [],
- expansions = [],
- userFields = [],
- topicFields = [],
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/spaces";
+ }
+ /**
+ * Get stream links
+ * Get a list of webhook links associated with a filtered stream ruleset.
+
+
+
+ * @returns {Promise} Promise resolving to the API response
+ */
+ // Overload 1: Default behavior (unwrapped response)
+ async getStreamLinks() {
+ let path = "/2/tweets/search/webhooks";
const params = new URLSearchParams();
- if (ids !== void 0 && ids.length > 0) {
- params.append("ids", ids.join(","));
- }
- if (spaceFields !== void 0 && spaceFields.length > 0) {
- params.append("space.fields", spaceFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (topicFields !== void 0 && topicFields.length > 0) {
- params.append("topic.fields", topicFields.join(","));
- }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
BearerToken: []
- },
- {
- OAuth2UserToken: ["space.read", "tweet.read", "users.read"]
}
- ],
- ...requestOptions
+ ]
+ // No optional parameters, using empty request options
};
return this.client.request(
"GET",
@@ -11907,14 +11355,14 @@ var SpacesClient = class {
}
};
-// src/spaces/models.ts
-var models_exports9 = {};
+// src/webhooks/models.ts
+var models_exports13 = {};
-// src/communities/client.ts
-var CommunitiesClient = class {
+// src/users/client.ts
+var UsersClient = class {
client;
/**
- * Creates a new communities client instance
+ * Creates a new users client instance
*
* @param client - The main X API client instance
*/
@@ -11939,35 +11387,46 @@ var CommunitiesClient = class {
return normalized;
}
/**
- * Get Community by ID
- * Retrieves details of a specific Community by its ID.
+ * Get Users by usernames
+ * Retrieves details of multiple Users by their usernames.
- * @param id The ID of the Community.
+ * @param usernames A list of usernames, comma-separated.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getById(id, options = {}) {
+ async getByUsernames(usernames, options = {}) {
const paramMappings = {
- "community.fields": "communityFields"
+ "user.fields": "userFields",
+ "tweet.fields": "tweetFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- communityFields = [],
+ userFields = [],
+ expansions = [],
+ tweetFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/communities/{id}";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/users/by";
const params = new URLSearchParams();
- if (communityFields !== void 0 && communityFields.length > 0) {
- params.append("community.fields", communityFields.join(","));
+ if (usernames !== void 0 && usernames.length > 0) {
+ params.append("usernames", usernames.join(","));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
@@ -11976,7 +11435,7 @@ var CommunitiesClient = class {
BearerToken: []
},
{
- OAuth2UserToken: ["list.read", "tweet.read", "users.read"]
+ OAuth2UserToken: ["tweet.read", "users.read"]
},
{
UserToken: []
@@ -11991,24 +11450,24 @@ var CommunitiesClient = class {
);
}
/**
- * Search Communities
- * Retrieves a list of Communities matching the specified search query.
+ * Get List memberships
+ * Retrieves a list of Lists that a specific User is a member of by their ID.
+ * @param id The ID of the User to lookup.
- * @param query Query to search communities.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async search(query, options = {}) {
+ async getListMemberships(id, options = {}) {
const paramMappings = {
max_results: "maxResults",
- next_token: "nextToken",
pagination_token: "paginationToken",
- "community.fields": "communityFields"
+ "list.fields": "listFields",
+ "user.fields": "userFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
@@ -12016,33 +11475,38 @@ var CommunitiesClient = class {
);
const {
maxResults = void 0,
- nextToken = void 0,
paginationToken = void 0,
- communityFields = [],
+ listFields = [],
+ expansions = [],
+ userFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/communities/search";
+ let path = "/2/users/{id}/list_memberships";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (query !== void 0) {
- params.append("query", String(query));
- }
if (maxResults !== void 0) {
params.append("max_results", String(maxResults));
}
- if (nextToken !== void 0) {
- params.append("next_token", String(nextToken));
- }
if (paginationToken !== void 0) {
params.append("pagination_token", String(paginationToken));
}
- if (communityFields !== void 0 && communityFields.length > 0) {
- params.append("community.fields", communityFields.join(","));
+ if (listFields !== void 0 && listFields.length > 0) {
+ params.append("list.fields", listFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["tweet.read", "users.read"]
+ BearerToken: []
+ },
+ {
+ OAuth2UserToken: ["list.read", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -12056,56 +11520,42 @@ var CommunitiesClient = class {
finalRequestOptions
);
}
-};
-
-// src/communities/models.ts
-var models_exports10 = {};
-
-// src/connections/client.ts
-var ConnectionsClient = class {
- client;
- /**
- * Creates a new connections client instance
- *
- * @param client - The main X API client instance
- */
- constructor(client) {
- this.client = client;
- }
- /**
- * Normalize options object to handle both camelCase and original API parameter names
- * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
- */
- _normalizeOptions(options, paramMappings) {
- if (!options || typeof options !== "object") {
- return options;
- }
- const normalized = { ...options };
- for (const [originalName, camelName] of Object.entries(paramMappings)) {
- if (originalName in normalized && !(camelName in normalized)) {
- normalized[camelName] = normalized[originalName];
- delete normalized[originalName];
- }
- }
- return normalized;
- }
/**
- * Terminate all connections
- * Terminates all active streaming connections for the authenticated application.
+ * Unfollow User
+ * Causes the authenticated user to unfollow a specific user by their ID.
+ * @param sourceUserId The ID of the authenticated source User that is requesting to unfollow the target User.
- * @returns {Promise} Promise resolving to the API response
+
+
+ * @param targetUserId The ID of the User that the source User is requesting to unfollow.
+
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async deleteAll() {
- let path = "/2/connections/all";
+ async unfollowUser(sourceUserId, targetUserId) {
+ let path = "/2/users/{source_user_id}/following/{target_user_id}";
+ path = path.replace(
+ "{source_user_id}",
+ encodeURIComponent(String(sourceUserId))
+ );
+ path = path.replace(
+ "{target_user_id}",
+ encodeURIComponent(String(targetUserId))
+ );
const params = new URLSearchParams();
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
+ OAuth2UserToken: ["follows.write", "tweet.read", "users.read"]
+ },
+ {
+ UserToken: []
}
]
// No optional parameters, using empty request options
@@ -12116,134 +11566,96 @@ var ConnectionsClient = class {
finalRequestOptions
);
}
-};
-
-// src/connections/models.ts
-var models_exports11 = {};
-
-// src/media/client.ts
-var MediaClient = class {
- client;
- /**
- * Creates a new media client instance
- *
- * @param client - The main X API client instance
- */
- constructor(client) {
- this.client = client;
- }
- /**
- * Normalize options object to handle both camelCase and original API parameter names
- * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
- */
- _normalizeOptions(options, paramMappings) {
- if (!options || typeof options !== "object") {
- return options;
- }
- const normalized = { ...options };
- for (const [originalName, camelName] of Object.entries(paramMappings)) {
- if (originalName in normalized && !(camelName in normalized)) {
- normalized[camelName] = normalized[originalName];
- delete normalized[originalName];
- }
- }
- return normalized;
- }
/**
- * Get Media analytics
- * Retrieves analytics data for media.
-
+ * Unfollow List
+ * Causes the authenticated user to unfollow a specific List by its ID.
- * @param mediaKeys A comma separated list of Media Keys. Up to 100 are allowed in a single request.
+ * @param id The ID of the authenticated source User that will unfollow the List.
- * @param endTime YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the end of the time range.
+ * @param listId The ID of the List to unfollow.
- * @param startTime YYYY-MM-DDTHH:mm:ssZ. The UTC timestamp representing the start of the time range.
-
-
- * @param granularity The granularity for the search counts results.
-
-
-
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getAnalytics(mediaKeys, endTime, startTime, granularity, options = {}) {
- const paramMappings = {
- "media_analytics.fields": "mediaAnalyticsFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
- const {
- mediaAnalyticsFields = [],
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/media/analytics";
+ async unfollowList(id, listId) {
+ let path = "/2/users/{id}/followed_lists/{list_id}";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
+ path = path.replace("{list_id}", encodeURIComponent(String(listId)));
const params = new URLSearchParams();
- if (mediaKeys !== void 0 && mediaKeys.length > 0) {
- params.append("media_keys", mediaKeys.join(","));
- }
- if (endTime !== void 0) {
- params.append("end_time", String(endTime));
- }
- if (startTime !== void 0) {
- params.append("start_time", String(startTime));
- }
- if (granularity !== void 0) {
- params.append("granularity", String(granularity));
- }
- if (mediaAnalyticsFields !== void 0 && mediaAnalyticsFields.length > 0) {
- params.append("media_analytics.fields", mediaAnalyticsFields.join(","));
- }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["tweet.read"]
+ OAuth2UserToken: ["list.write", "tweet.read", "users.read"]
},
{
UserToken: []
}
- ],
- ...requestOptions
+ ]
+ // No optional parameters, using empty request options
};
return this.client.request(
- "GET",
+ "DELETE",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Create Media subtitles
- * Creates subtitles for a specific Media file.
+ * Get Users by IDs
+ * Retrieves details of multiple Users by their IDs.
- * @returns {Promise} Promise resolving to the API response
+ * @param ids A list of User IDs, comma-separated. You can specify up to 100 IDs.
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async createSubtitles(options = {}) {
- const normalizedOptions = options || {};
+ async getByIds(ids, options = {}) {
+ const paramMappings = {
+ "user.fields": "userFields",
+ "tweet.fields": "tweetFields"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
const {
- body,
+ userFields = [],
+ expansions = [],
+ tweetFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/media/subtitles";
+ let path = "/2/users";
const params = new URLSearchParams();
+ if (ids !== void 0 && ids.length > 0) {
+ params.append("ids", ids.join(","));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
const finalRequestOptions = {
- body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["media.write"]
+ BearerToken: []
+ },
+ {
+ OAuth2UserToken: ["tweet.read", "users.read"]
},
{
UserToken: []
@@ -12252,34 +11664,39 @@ var MediaClient = class {
...requestOptions
};
return this.client.request(
- "POST",
+ "GET",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Delete Media subtitles
- * Deletes subtitles for a specific Media file.
+ * Like Post
+ * Causes the authenticated user to Like a specific Post by its ID.
+
+ * @param id The ID of the authenticated source User that is requesting to like the Post.
- * @returns {Promise} Promise resolving to the API response
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async deleteSubtitles(options = {}) {
+ async likePost(id, options = {}) {
const normalizedOptions = options || {};
const {
body,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/media/subtitles";
+ let path = "/2/users/{id}/likes";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
const finalRequestOptions = {
body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["media.write"]
+ OAuth2UserToken: ["like.write", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -12288,40 +11705,39 @@ var MediaClient = class {
...requestOptions
};
return this.client.request(
- "DELETE",
+ "POST",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Initialize media upload
- * Initializes a media upload.
+ * Block DMs
+ * Blocks direct messages to or from a specific User by their ID for the authenticated user.
+ * @param id The ID of the target User that the authenticated user requesting to block dms for.
- * @returns {Promise} Promise resolving to the API response
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async initializeUpload(options = {}) {
- const normalizedOptions = options || {};
- const {
- body,
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/media/upload/initialize";
+ async blockDms(id) {
+ let path = "/2/users/{id}/dm/block";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
const finalRequestOptions = {
- body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["media.write"]
+ OAuth2UserToken: ["dm.write", "tweet.read", "users.read"]
},
{
UserToken: []
}
- ],
- ...requestOptions
+ ]
+ // No optional parameters, using empty request options
};
return this.client.request(
"POST",
@@ -12330,41 +11746,102 @@ var MediaClient = class {
);
}
/**
- * Get Media upload status
- * Retrieves the status of a Media upload by its ID.
+ * Get Posts
+ * Retrieves a list of posts authored by a specific User by their ID.
+ * @param id The ID of the User to lookup.
- * @param mediaId Media id for the requested media upload status.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getUploadStatus(mediaId, options = {}) {
- const paramMappings = {};
+ async getPosts(id, options = {}) {
+ const paramMappings = {
+ since_id: "sinceId",
+ until_id: "untilId",
+ max_results: "maxResults",
+ pagination_token: "paginationToken",
+ start_time: "startTime",
+ end_time: "endTime",
+ "tweet.fields": "tweetFields",
+ "media.fields": "mediaFields",
+ "poll.fields": "pollFields",
+ "user.fields": "userFields",
+ "place.fields": "placeFields"
+ };
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- command = void 0,
+ sinceId = void 0,
+ untilId = void 0,
+ maxResults = void 0,
+ paginationToken = void 0,
+ exclude = [],
+ startTime = void 0,
+ endTime = void 0,
+ tweetFields = [],
+ expansions = [],
+ mediaFields = [],
+ pollFields = [],
+ userFields = [],
+ placeFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/media/upload";
+ let path = "/2/users/{id}/tweets";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (mediaId !== void 0) {
- params.append("media_id", String(mediaId));
+ if (sinceId !== void 0) {
+ params.append("since_id", String(sinceId));
}
- if (command !== void 0) {
- params.append("command", String(command));
+ if (untilId !== void 0) {
+ params.append("until_id", String(untilId));
+ }
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
+ }
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
+ }
+ if (exclude !== void 0 && exclude.length > 0) {
+ params.append("exclude", exclude.join(","));
+ }
+ if (startTime !== void 0) {
+ params.append("start_time", String(startTime));
+ }
+ if (endTime !== void 0) {
+ params.append("end_time", String(endTime));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (mediaFields !== void 0 && mediaFields.length > 0) {
+ params.append("media.fields", mediaFields.join(","));
+ }
+ if (pollFields !== void 0 && pollFields.length > 0) {
+ params.append("poll.fields", pollFields.join(","));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (placeFields !== void 0 && placeFields.length > 0) {
+ params.append("place.fields", placeFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["media.write"]
+ BearerToken: []
+ },
+ {
+ OAuth2UserToken: ["tweet.read", "users.read"]
},
{
UserToken: []
@@ -12379,80 +11856,97 @@ var MediaClient = class {
);
}
/**
- * Upload media
- * Uploads a media file for use in posts or other content.
+ * Get Bookmarks by folder ID
+ * Retrieves Posts in a specific Bookmark folder by its ID for the authenticated user.
+ * @param id The ID of the authenticated source User for whom to return results.
- * @returns {Promise} Promise resolving to the API response
+
+
+ * @param folderId The ID of the Bookmark Folder that the authenticated User is trying to fetch Posts for.
+
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async upload(options = {}) {
- const normalizedOptions = options || {};
- const {
- body,
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/media/upload";
+ async getBookmarksByFolderId(id, folderId) {
+ let path = "/2/users/{id}/bookmarks/folders/{folder_id}";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
+ path = path.replace("{folder_id}", encodeURIComponent(String(folderId)));
const params = new URLSearchParams();
const finalRequestOptions = {
- body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["media.write"]
- },
- {
- UserToken: []
+ OAuth2UserToken: ["bookmark.read", "tweet.read", "users.read"]
}
- ],
- ...requestOptions
+ ]
+ // No optional parameters, using empty request options
};
return this.client.request(
- "POST",
+ "GET",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get Media by media key
- * Retrieves details of a specific Media file by its media key.
+ * Get muting
+ * Retrieves a list of Users muted by the authenticated user.
- * @param mediaKey A single Media Key.
+ * @param id The ID of the authenticated source User for whom to return results.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getByKey(mediaKey, options = {}) {
+ async getMuting(id, options = {}) {
const paramMappings = {
- "media.fields": "mediaFields"
+ max_results: "maxResults",
+ pagination_token: "paginationToken",
+ "user.fields": "userFields",
+ "tweet.fields": "tweetFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- mediaFields = [],
+ maxResults = void 0,
+ paginationToken = void 0,
+ userFields = [],
+ expansions = [],
+ tweetFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/media/{media_key}";
- path = path.replace("{media_key}", encodeURIComponent(String(mediaKey)));
+ let path = "/2/users/{id}/muting";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (mediaFields !== void 0 && mediaFields.length > 0) {
- params.append("media.fields", mediaFields.join(","));
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
+ }
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
- },
- {
- OAuth2UserToken: ["tweet.read"]
+ OAuth2UserToken: ["mute.read", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -12467,25 +11961,25 @@ var MediaClient = class {
);
}
/**
- * Append Media upload
- * Appends data to a Media upload request.
+ * Mute User
+ * Causes the authenticated user to mute a specific User by their ID.
- * @param id The media identifier for the media to perform the append operation.
+ * @param id The ID of the authenticated source User that is requesting to mute the target User.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async appendUpload(id, options = {}) {
+ async muteUser(id, options = {}) {
const normalizedOptions = options || {};
const {
body,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/media/upload/{id}/append";
+ let path = "/2/users/{id}/muting";
path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
const finalRequestOptions = {
@@ -12493,7 +11987,7 @@ var MediaClient = class {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["media.write"]
+ OAuth2UserToken: ["mute.write", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -12508,37 +12002,54 @@ var MediaClient = class {
);
}
/**
- * Get Media by media keys
- * Retrieves details of Media files by their media keys.
+ * Get owned Lists
+ * Retrieves a list of Lists owned by a specific User by their ID.
+ * @param id The ID of the User to lookup.
- * @param mediaKeys A comma separated list of Media Keys. Up to 100 are allowed in a single request.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getByKeys(mediaKeys, options = {}) {
+ async getOwnedLists(id, options = {}) {
const paramMappings = {
- "media.fields": "mediaFields"
+ max_results: "maxResults",
+ pagination_token: "paginationToken",
+ "list.fields": "listFields",
+ "user.fields": "userFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- mediaFields = [],
+ maxResults = void 0,
+ paginationToken = void 0,
+ listFields = [],
+ expansions = [],
+ userFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/media";
+ let path = "/2/users/{id}/owned_lists";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (mediaKeys !== void 0 && mediaKeys.length > 0) {
- params.append("media_keys", mediaKeys.join(","));
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
}
- if (mediaFields !== void 0 && mediaFields.length > 0) {
- params.append("media.fields", mediaFields.join(","));
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
+ }
+ if (listFields !== void 0 && listFields.length > 0) {
+ params.append("list.fields", listFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
@@ -12547,7 +12058,7 @@ var MediaClient = class {
BearerToken: []
},
{
- OAuth2UserToken: ["tweet.read"]
+ OAuth2UserToken: ["list.read", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -12562,27 +12073,32 @@ var MediaClient = class {
);
}
/**
- * Finalize Media upload
- * Finalizes a Media upload request.
+ * Unpin List
+ * Causes the authenticated user to unpin a specific List by its ID.
- * @param id The media id of the targeted media to finalize.
+ * @param id The ID of the authenticated source User for whom to return results.
+ * @param listId The ID of the List to unpin.
- * @returns {Promise} Promise resolving to the API response
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async finalizeUpload(id) {
- let path = "/2/media/upload/{id}/finalize";
+ async unpinList(id, listId) {
+ let path = "/2/users/{id}/pinned_lists/{list_id}";
path = path.replace("{id}", encodeURIComponent(String(id)));
+ path = path.replace("{list_id}", encodeURIComponent(String(listId)));
const params = new URLSearchParams();
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["media.write"]
+ OAuth2UserToken: ["list.write", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -12591,34 +12107,59 @@ var MediaClient = class {
// No optional parameters, using empty request options
};
return this.client.request(
- "POST",
+ "DELETE",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Create Media metadata
- * Creates metadata for a Media file.
+ * Get User by username
+ * Retrieves details of a specific User by their username.
+
+ * @param username A username.
- * @returns {Promise} Promise resolving to the API response
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async createMetadata(options = {}) {
- const normalizedOptions = options || {};
+ async getByUsername(username, options = {}) {
+ const paramMappings = {
+ "user.fields": "userFields",
+ "tweet.fields": "tweetFields"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
const {
- body,
+ userFields = [],
+ expansions = [],
+ tweetFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/media/metadata";
+ let path = "/2/users/by/username/{username}";
+ path = path.replace("{username}", encodeURIComponent(String(username)));
const params = new URLSearchParams();
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
const finalRequestOptions = {
- body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["media.write"]
+ BearerToken: []
+ },
+ {
+ OAuth2UserToken: ["tweet.read", "users.read"]
},
{
UserToken: []
@@ -12627,132 +12168,66 @@ var MediaClient = class {
...requestOptions
};
return this.client.request(
- "POST",
+ "GET",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
-};
-
-// src/media/models.ts
-var models_exports12 = {};
-
-// src/lists/client.ts
-var ListsClient = class {
- client;
- /**
- * Creates a new lists client instance
- *
- * @param client - The main X API client instance
- */
- constructor(client) {
- this.client = client;
- }
- /**
- * Normalize options object to handle both camelCase and original API parameter names
- * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
- */
- _normalizeOptions(options, paramMappings) {
- if (!options || typeof options !== "object") {
- return options;
- }
- const normalized = { ...options };
- for (const [originalName, camelName] of Object.entries(paramMappings)) {
- if (originalName in normalized && !(camelName in normalized)) {
- normalized[camelName] = normalized[originalName];
- delete normalized[originalName];
- }
- }
- return normalized;
- }
/**
- * Remove List member
- * Removes a User from a specific List by its ID and the User’s ID.
-
-
- * @param id The ID of the List to remove a member.
-
+ * Get blocking
+ * Retrieves a list of Users blocked by the specified User ID.
- * @param userId The ID of User that will be removed from the List.
+ * @param id The ID of the authenticated source User for whom to return results.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async removeMemberByUserId(id, userId) {
- let path = "/2/lists/{id}/members/{user_id}";
- path = path.replace("{id}", encodeURIComponent(String(id)));
- path = path.replace("{user_id}", encodeURIComponent(String(userId)));
- const params = new URLSearchParams();
- const finalRequestOptions = {
- // Pass security requirements for smart auth selection
- security: [
- {
- OAuth2UserToken: ["list.write", "tweet.read", "users.read"]
- },
- {
- UserToken: []
- }
- ]
- // No optional parameters, using empty request options
+ async getBlocking(id, options = {}) {
+ const paramMappings = {
+ max_results: "maxResults",
+ pagination_token: "paginationToken",
+ "user.fields": "userFields",
+ "tweet.fields": "tweetFields"
};
- return this.client.request(
- "DELETE",
- path + (params.toString() ? `?${params.toString()}` : ""),
- finalRequestOptions
- );
- }
- /**
- * Get List by ID
- * Retrieves details of a specific List by its ID.
-
-
- * @param id The ID of the List.
-
-
-
-
- * @returns {Promise} Promise resolving to the API response
- */
- // Overload 1: Default behavior (unwrapped response)
- async getById(id, options = {}) {
- const paramMappings = {
- "list.fields": "listFields",
- "user.fields": "userFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
);
const {
- listFields = [],
- expansions = [],
+ maxResults = void 0,
+ paginationToken = void 0,
userFields = [],
+ expansions = [],
+ tweetFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/lists/{id}";
+ let path = "/2/users/{id}/blocking";
path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (listFields !== void 0 && listFields.length > 0) {
- params.append("list.fields", listFields.join(","));
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
}
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
}
if (userFields !== void 0 && userFields.length > 0) {
params.append("user.fields", userFields.join(","));
}
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
- },
- {
- OAuth2UserToken: ["list.read", "tweet.read", "users.read"]
+ OAuth2UserToken: ["block.read", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -12767,33 +12242,75 @@ var ListsClient = class {
);
}
/**
- * Update List
- * Updates the details of a specific List owned by the authenticated user by its ID.
+ * Get liked Posts
+ * Retrieves a list of Posts liked by a specific User by their ID.
- * @param id The ID of the List to modify.
+ * @param id The ID of the User to lookup.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async update(id, options = {}) {
- const normalizedOptions = options || {};
+ async getLikedPosts(id, options = {}) {
+ const paramMappings = {
+ max_results: "maxResults",
+ pagination_token: "paginationToken",
+ "tweet.fields": "tweetFields",
+ "media.fields": "mediaFields",
+ "poll.fields": "pollFields",
+ "user.fields": "userFields",
+ "place.fields": "placeFields"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
const {
- body,
+ maxResults = void 0,
+ paginationToken = void 0,
+ tweetFields = [],
+ expansions = [],
+ mediaFields = [],
+ pollFields = [],
+ userFields = [],
+ placeFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/lists/{id}";
+ let path = "/2/users/{id}/liked_tweets";
path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
+ }
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (mediaFields !== void 0 && mediaFields.length > 0) {
+ params.append("media.fields", mediaFields.join(","));
+ }
+ if (pollFields !== void 0 && pollFields.length > 0) {
+ params.append("poll.fields", pollFields.join(","));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (placeFields !== void 0 && placeFields.length > 0) {
+ params.append("place.fields", placeFields.join(","));
+ }
const finalRequestOptions = {
- body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["list.write", "tweet.read", "users.read"]
+ OAuth2UserToken: ["like.read", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -12802,33 +12319,38 @@ var ListsClient = class {
...requestOptions
};
return this.client.request(
- "PUT",
+ "GET",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Delete List
- * Deletes a specific List owned by the authenticated user by its ID.
+ * Unlike Post
+ * Causes the authenticated user to Unlike a specific Post by its ID.
- * @param id The ID of the List to delete.
+ * @param id The ID of the authenticated source User that is requesting to unlike the Post.
+ * @param tweetId The ID of the Post that the User is requesting to unlike.
- * @returns {Promise} Promise resolving to the API response
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async delete(id) {
- let path = "/2/lists/{id}";
+ async unlikePost(id, tweetId) {
+ let path = "/2/users/{id}/likes/{tweet_id}";
path = path.replace("{id}", encodeURIComponent(String(id)));
+ path = path.replace("{tweet_id}", encodeURIComponent(String(tweetId)));
const params = new URLSearchParams();
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["list.write", "tweet.read", "users.read"]
+ OAuth2UserToken: ["like.write", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -12843,24 +12365,24 @@ var ListsClient = class {
);
}
/**
- * Get List members
- * Retrieves a list of Users who are members of a specific List by its ID.
+ * Get followed Lists
+ * Retrieves a list of Lists followed by a specific User by their ID.
- * @param id The ID of the List.
+ * @param id The ID of the User to lookup.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getMembers(id, options = {}) {
+ async getFollowedLists(id, options = {}) {
const paramMappings = {
max_results: "maxResults",
pagination_token: "paginationToken",
- "user.fields": "userFields",
- "tweet.fields": "tweetFields"
+ "list.fields": "listFields",
+ "user.fields": "userFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
@@ -12869,12 +12391,12 @@ var ListsClient = class {
const {
maxResults = void 0,
paginationToken = void 0,
- userFields = [],
+ listFields = [],
expansions = [],
- tweetFields = [],
+ userFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/lists/{id}/members";
+ let path = "/2/users/{id}/followed_lists";
path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
if (maxResults !== void 0) {
@@ -12883,14 +12405,14 @@ var ListsClient = class {
if (paginationToken !== void 0) {
params.append("pagination_token", String(paginationToken));
}
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
+ if (listFields !== void 0 && listFields.length > 0) {
+ params.append("list.fields", listFields.join(","));
}
if (expansions !== void 0 && expansions.length > 0) {
params.append("expansions", expansions.join(","));
}
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
@@ -12914,25 +12436,25 @@ var ListsClient = class {
);
}
/**
- * Add List member
- * Adds a User to a specific List by its ID.
+ * Follow List
+ * Causes the authenticated user to follow a specific List by its ID.
- * @param id The ID of the List for which to add a member.
+ * @param id The ID of the authenticated source User that will follow the List.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async addMember(id, options = {}) {
+ async followList(id, options = {}) {
const normalizedOptions = options || {};
const {
body,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/lists/{id}/members";
+ let path = "/2/users/{id}/followed_lists";
path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
const finalRequestOptions = {
@@ -12955,63 +12477,99 @@ var ListsClient = class {
);
}
/**
- * Get List followers
- * Retrieves a list of Users who follow a specific List by its ID.
+ * Get Timeline
+ * Retrieves a reverse chronological list of Posts in the authenticated User’s Timeline.
- * @param id The ID of the List.
+ * @param id The ID of the authenticated source User to list Reverse Chronological Timeline Posts of.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getFollowers(id, options = {}) {
+ async getTimeline(id, options = {}) {
const paramMappings = {
+ since_id: "sinceId",
+ until_id: "untilId",
max_results: "maxResults",
pagination_token: "paginationToken",
+ start_time: "startTime",
+ end_time: "endTime",
+ "tweet.fields": "tweetFields",
+ "media.fields": "mediaFields",
+ "poll.fields": "pollFields",
"user.fields": "userFields",
- "tweet.fields": "tweetFields"
+ "place.fields": "placeFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
+ sinceId = void 0,
+ untilId = void 0,
maxResults = void 0,
paginationToken = void 0,
- userFields = [],
- expansions = [],
+ exclude = [],
+ startTime = void 0,
+ endTime = void 0,
tweetFields = [],
+ expansions = [],
+ mediaFields = [],
+ pollFields = [],
+ userFields = [],
+ placeFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/lists/{id}/followers";
+ let path = "/2/users/{id}/timelines/reverse_chronological";
path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
+ if (sinceId !== void 0) {
+ params.append("since_id", String(sinceId));
+ }
+ if (untilId !== void 0) {
+ params.append("until_id", String(untilId));
+ }
if (maxResults !== void 0) {
params.append("max_results", String(maxResults));
}
if (paginationToken !== void 0) {
params.append("pagination_token", String(paginationToken));
}
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
+ if (exclude !== void 0 && exclude.length > 0) {
+ params.append("exclude", exclude.join(","));
}
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
+ if (startTime !== void 0) {
+ params.append("start_time", String(startTime));
+ }
+ if (endTime !== void 0) {
+ params.append("end_time", String(endTime));
}
if (tweetFields !== void 0 && tweetFields.length > 0) {
params.append("tweet.fields", tweetFields.join(","));
}
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (mediaFields !== void 0 && mediaFields.length > 0) {
+ params.append("media.fields", mediaFields.join(","));
+ }
+ if (pollFields !== void 0 && pollFields.length > 0) {
+ params.append("poll.fields", pollFields.join(","));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (placeFields !== void 0 && placeFields.length > 0) {
+ params.append("place.fields", placeFields.join(","));
+ }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
- },
- {
- OAuth2UserToken: ["list.read", "tweet.read", "users.read"]
+ OAuth2UserToken: ["tweet.read", "users.read"]
},
{
UserToken: []
@@ -13026,76 +12584,48 @@ var ListsClient = class {
);
}
/**
- * Get List Posts
- * Retrieves a list of Posts associated with a specific List by its ID.
+ * Get pinned Lists
+ * Retrieves a list of Lists pinned by the authenticated user.
- * @param id The ID of the List.
+ * @param id The ID of the authenticated source User for whom to return results.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getPosts(id, options = {}) {
+ async getPinnedLists(id, options = {}) {
const paramMappings = {
- max_results: "maxResults",
- pagination_token: "paginationToken",
- "tweet.fields": "tweetFields",
- "media.fields": "mediaFields",
- "poll.fields": "pollFields",
- "user.fields": "userFields",
- "place.fields": "placeFields"
+ "list.fields": "listFields",
+ "user.fields": "userFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- maxResults = void 0,
- paginationToken = void 0,
- tweetFields = [],
+ listFields = [],
expansions = [],
- mediaFields = [],
- pollFields = [],
userFields = [],
- placeFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/lists/{id}/tweets";
+ let path = "/2/users/{id}/pinned_lists";
path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
- }
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ if (listFields !== void 0 && listFields.length > 0) {
+ params.append("list.fields", listFields.join(","));
}
if (expansions !== void 0 && expansions.length > 0) {
params.append("expansions", expansions.join(","));
}
- if (mediaFields !== void 0 && mediaFields.length > 0) {
- params.append("media.fields", mediaFields.join(","));
- }
- if (pollFields !== void 0 && pollFields.length > 0) {
- params.append("poll.fields", pollFields.join(","));
- }
if (userFields !== void 0 && userFields.length > 0) {
params.append("user.fields", userFields.join(","));
}
- if (placeFields !== void 0 && placeFields.length > 0) {
- params.append("place.fields", placeFields.join(","));
- }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
- {
- BearerToken: []
- },
{
OAuth2UserToken: ["list.read", "tweet.read", "users.read"]
},
@@ -13112,39 +12642,36 @@ var ListsClient = class {
);
}
/**
- * Create List
- * Creates a new List for the authenticated user.
+ * Pin List
+ * Causes the authenticated user to pin a specific List by its ID.
+
+ * @param id The ID of the authenticated source User that will pin the List.
- * @returns {Promise} Promise resolving to the API response
+
+
+ * @param body Request body
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async create(options = {}) {
- const normalizedOptions = options || {};
- const {
- body,
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/lists";
+ async pinList(id, body) {
+ let path = "/2/users/{id}/pinned_lists";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
const finalRequestOptions = {
- body: body ? JSON.stringify(body) : void 0,
+ body: JSON.stringify(body || {}),
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: [
- "list.read",
- "list.write",
- "tweet.read",
- "users.read"
- ]
+ OAuth2UserToken: ["list.write", "tweet.read", "users.read"]
},
{
UserToken: []
}
- ],
- ...requestOptions
+ ]
+ // No optional parameters, using empty request options
};
return this.client.request(
"POST",
@@ -13152,75 +12679,74 @@ var ListsClient = class {
finalRequestOptions
);
}
-};
-
-// src/lists/models.ts
-var models_exports13 = {};
-
-// src/compliance/client.ts
-var ComplianceClient = class {
- client;
- /**
- * Creates a new compliance client instance
- *
- * @param client - The main X API client instance
- */
- constructor(client) {
- this.client = client;
- }
- /**
- * Normalize options object to handle both camelCase and original API parameter names
- * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
- */
- _normalizeOptions(options, paramMappings) {
- if (!options || typeof options !== "object") {
- return options;
- }
- const normalized = { ...options };
- for (const [originalName, camelName] of Object.entries(paramMappings)) {
- if (originalName in normalized && !(camelName in normalized)) {
- normalized[camelName] = normalized[originalName];
- delete normalized[originalName];
- }
- }
- return normalized;
- }
/**
- * Get Compliance Job by ID
- * Retrieves details of a specific Compliance Job by its ID.
-
-
- * @param id The ID of the Compliance Job to retrieve.
-
+ * Get Reposts of me
+ * Retrieves a list of Posts that repost content from the authenticated user.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getJobsById(id, options = {}) {
+ async getRepostsOfMe(options = {}) {
const paramMappings = {
- "compliance_job.fields": "complianceJobFields"
+ max_results: "maxResults",
+ pagination_token: "paginationToken",
+ "tweet.fields": "tweetFields",
+ "media.fields": "mediaFields",
+ "poll.fields": "pollFields",
+ "user.fields": "userFields",
+ "place.fields": "placeFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- complianceJobFields = [],
+ maxResults = void 0,
+ paginationToken = void 0,
+ tweetFields = [],
+ expansions = [],
+ mediaFields = [],
+ pollFields = [],
+ userFields = [],
+ placeFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/compliance/jobs/{id}";
- path = path.replace("{id}", encodeURIComponent(String(id)));
+ let path = "/2/users/reposts_of_me";
const params = new URLSearchParams();
- if (complianceJobFields !== void 0 && complianceJobFields.length > 0) {
- params.append("compliance_job.fields", complianceJobFields.join(","));
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
+ }
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (mediaFields !== void 0 && mediaFields.length > 0) {
+ params.append("media.fields", mediaFields.join(","));
+ }
+ if (pollFields !== void 0 && pollFields.length > 0) {
+ params.append("poll.fields", pollFields.join(","));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (placeFields !== void 0 && placeFields.length > 0) {
+ params.append("place.fields", placeFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
+ OAuth2UserToken: ["timeline.read", "tweet.read"]
+ },
+ {
+ UserToken: []
}
],
...requestOptions
@@ -13232,47 +12758,66 @@ var ComplianceClient = class {
);
}
/**
- * Get Compliance Jobs
- * Retrieves a list of Compliance Jobs filtered by job type and optional status.
+ * Get following
+ * Retrieves a list of Users followed by a specific User by their ID.
+ * @param id The ID of the User to lookup.
- * @param type Type of Compliance Job to list.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getJobs(type, options = {}) {
+ async getFollowing(id, options = {}) {
const paramMappings = {
- "compliance_job.fields": "complianceJobFields"
+ max_results: "maxResults",
+ pagination_token: "paginationToken",
+ "user.fields": "userFields",
+ "tweet.fields": "tweetFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- status = void 0,
- complianceJobFields = [],
+ maxResults = void 0,
+ paginationToken = void 0,
+ userFields = [],
+ expansions = [],
+ tweetFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/compliance/jobs";
+ let path = "/2/users/{id}/following";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (type !== void 0) {
- params.append("type", String(type));
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
}
- if (status !== void 0) {
- params.append("status", String(status));
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
}
- if (complianceJobFields !== void 0 && complianceJobFields.length > 0) {
- params.append("compliance_job.fields", complianceJobFields.join(","));
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
BearerToken: []
+ },
+ {
+ OAuth2UserToken: ["follows.read", "tweet.read", "users.read"]
+ },
+ {
+ UserToken: []
}
],
...requestOptions
@@ -13284,28 +12829,39 @@ var ComplianceClient = class {
);
}
/**
- * Create Compliance Job
- * Creates a new Compliance Job for the specified job type.
+ * Follow User
+ * Causes the authenticated user to follow a specific user by their ID.
+ * @param id The ID of the authenticated source User that is requesting to follow the target User.
- * @param body Request body
- * @returns {Promise} Promise resolving to the API response
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async createJobs(body) {
- let path = "/2/compliance/jobs";
+ async followUser(id, options = {}) {
+ const normalizedOptions = options || {};
+ const {
+ body,
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/users/{id}/following";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
const finalRequestOptions = {
- body: JSON.stringify(body || {}),
+ body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
+ OAuth2UserToken: ["follows.write", "tweet.read", "users.read"]
+ },
+ {
+ UserToken: []
}
- ]
- // No optional parameters, using empty request options
+ ],
+ ...requestOptions
};
return this.client.request(
"POST",
@@ -13313,53 +12869,443 @@ var ComplianceClient = class {
finalRequestOptions
);
}
-};
-
-// src/compliance/models.ts
-var models_exports14 = {};
-
-// src/general/client.ts
-var GeneralClient = class {
- client;
/**
- * Creates a new general client instance
- *
- * @param client - The main X API client instance
- */
- constructor(client) {
- this.client = client;
+ * Unblock DMs
+ * Unblocks direct messages to or from a specific User by their ID for the authenticated user.
+
+
+ * @param id The ID of the target User that the authenticated user requesting to unblock dms for.
+
+
+
+
+ * @returns {Promise} Promise resolving to the API response
+ */
+ // Overload 1: Default behavior (unwrapped response)
+ async unblockDms(id) {
+ let path = "/2/users/{id}/dm/unblock";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
+ const params = new URLSearchParams();
+ const finalRequestOptions = {
+ // Pass security requirements for smart auth selection
+ security: [
+ {
+ OAuth2UserToken: ["dm.write", "tweet.read", "users.read"]
+ },
+ {
+ UserToken: []
+ }
+ ]
+ // No optional parameters, using empty request options
+ };
+ return this.client.request(
+ "POST",
+ path + (params.toString() ? `?${params.toString()}` : ""),
+ finalRequestOptions
+ );
+ }
+ /**
+ * Get mentions
+ * Retrieves a list of Posts that mention a specific User by their ID.
+
+
+ * @param id The ID of the User to lookup.
+
+
+
+
+ * @returns {Promise} Promise resolving to the API response
+ */
+ // Overload 1: Default behavior (unwrapped response)
+ async getMentions(id, options = {}) {
+ const paramMappings = {
+ since_id: "sinceId",
+ until_id: "untilId",
+ max_results: "maxResults",
+ pagination_token: "paginationToken",
+ start_time: "startTime",
+ end_time: "endTime",
+ "tweet.fields": "tweetFields",
+ "media.fields": "mediaFields",
+ "poll.fields": "pollFields",
+ "user.fields": "userFields",
+ "place.fields": "placeFields"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
+ const {
+ sinceId = void 0,
+ untilId = void 0,
+ maxResults = void 0,
+ paginationToken = void 0,
+ startTime = void 0,
+ endTime = void 0,
+ tweetFields = [],
+ expansions = [],
+ mediaFields = [],
+ pollFields = [],
+ userFields = [],
+ placeFields = [],
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/users/{id}/mentions";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
+ const params = new URLSearchParams();
+ if (sinceId !== void 0) {
+ params.append("since_id", String(sinceId));
+ }
+ if (untilId !== void 0) {
+ params.append("until_id", String(untilId));
+ }
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
+ }
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
+ }
+ if (startTime !== void 0) {
+ params.append("start_time", String(startTime));
+ }
+ if (endTime !== void 0) {
+ params.append("end_time", String(endTime));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (mediaFields !== void 0 && mediaFields.length > 0) {
+ params.append("media.fields", mediaFields.join(","));
+ }
+ if (pollFields !== void 0 && pollFields.length > 0) {
+ params.append("poll.fields", pollFields.join(","));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (placeFields !== void 0 && placeFields.length > 0) {
+ params.append("place.fields", placeFields.join(","));
+ }
+ const finalRequestOptions = {
+ // Pass security requirements for smart auth selection
+ security: [
+ {
+ BearerToken: []
+ },
+ {
+ OAuth2UserToken: ["tweet.read", "users.read"]
+ },
+ {
+ UserToken: []
+ }
+ ],
+ ...requestOptions
+ };
+ return this.client.request(
+ "GET",
+ path + (params.toString() ? `?${params.toString()}` : ""),
+ finalRequestOptions
+ );
+ }
+ /**
+ * Get Bookmark folders
+ * Retrieves a list of Bookmark folders created by the authenticated user.
+
+
+ * @param id The ID of the authenticated source User for whom to return results.
+
+
+
+
+ * @returns {Promise} Promise resolving to the API response
+ */
+ // Overload 1: Default behavior (unwrapped response)
+ async getBookmarkFolders(id, options = {}) {
+ const paramMappings = {
+ max_results: "maxResults",
+ pagination_token: "paginationToken"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
+ const {
+ maxResults = void 0,
+ paginationToken = void 0,
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/users/{id}/bookmarks/folders";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
+ const params = new URLSearchParams();
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
+ }
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
+ }
+ const finalRequestOptions = {
+ // Pass security requirements for smart auth selection
+ security: [
+ {
+ OAuth2UserToken: ["bookmark.read", "users.read"]
+ }
+ ],
+ ...requestOptions
+ };
+ return this.client.request(
+ "GET",
+ path + (params.toString() ? `?${params.toString()}` : ""),
+ finalRequestOptions
+ );
+ }
+ /**
+ * Unrepost Post
+ * Causes the authenticated user to unrepost a specific Post by its ID.
+
+
+ * @param id The ID of the authenticated source User that is requesting to repost the Post.
+
+
+
+ * @param sourceTweetId The ID of the Post that the User is requesting to unretweet.
+
+
+
+
+ * @returns {Promise} Promise resolving to the API response
+ */
+ // Overload 1: Default behavior (unwrapped response)
+ async unrepostPost(id, sourceTweetId) {
+ let path = "/2/users/{id}/retweets/{source_tweet_id}";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
+ path = path.replace(
+ "{source_tweet_id}",
+ encodeURIComponent(String(sourceTweetId))
+ );
+ const params = new URLSearchParams();
+ const finalRequestOptions = {
+ // Pass security requirements for smart auth selection
+ security: [
+ {
+ OAuth2UserToken: ["tweet.read", "tweet.write", "users.read"]
+ },
+ {
+ UserToken: []
+ }
+ ]
+ // No optional parameters, using empty request options
+ };
+ return this.client.request(
+ "DELETE",
+ path + (params.toString() ? `?${params.toString()}` : ""),
+ finalRequestOptions
+ );
+ }
+ /**
+ * Delete Bookmark
+ * Removes a Post from the authenticated user’s Bookmarks by its ID.
+
+
+ * @param id The ID of the authenticated source User whose bookmark is to be removed.
+
+
+
+ * @param tweetId The ID of the Post that the source User is removing from bookmarks.
+
+
+
+
+ * @returns {Promise} Promise resolving to the API response
+ */
+ // Overload 1: Default behavior (unwrapped response)
+ async deleteBookmark(id, tweetId) {
+ let path = "/2/users/{id}/bookmarks/{tweet_id}";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
+ path = path.replace("{tweet_id}", encodeURIComponent(String(tweetId)));
+ const params = new URLSearchParams();
+ const finalRequestOptions = {
+ // Pass security requirements for smart auth selection
+ security: [
+ {
+ OAuth2UserToken: ["bookmark.write", "tweet.read", "users.read"]
+ }
+ ]
+ // No optional parameters, using empty request options
+ };
+ return this.client.request(
+ "DELETE",
+ path + (params.toString() ? `?${params.toString()}` : ""),
+ finalRequestOptions
+ );
+ }
+ /**
+ * Repost Post
+ * Causes the authenticated user to repost a specific Post by its ID.
+
+
+ * @param id The ID of the authenticated source User that is requesting to repost the Post.
+
+
+
+
+ * @returns {Promise} Promise resolving to the API response
+ */
+ // Overload 1: Default behavior (unwrapped response)
+ async repostPost(id, options = {}) {
+ const normalizedOptions = options || {};
+ const {
+ body,
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/users/{id}/retweets";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
+ const params = new URLSearchParams();
+ const finalRequestOptions = {
+ body: body ? JSON.stringify(body) : void 0,
+ // Pass security requirements for smart auth selection
+ security: [
+ {
+ OAuth2UserToken: ["tweet.read", "tweet.write", "users.read"]
+ },
+ {
+ UserToken: []
+ }
+ ],
+ ...requestOptions
+ };
+ return this.client.request(
+ "POST",
+ path + (params.toString() ? `?${params.toString()}` : ""),
+ finalRequestOptions
+ );
}
/**
- * Normalize options object to handle both camelCase and original API parameter names
- * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
+ * Search Users
+ * Retrieves a list of Users matching a search query.
+
+
+
+ * @param query TThe the query string by which to query for users.
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
- _normalizeOptions(options, paramMappings) {
- if (!options || typeof options !== "object") {
- return options;
+ // Overload 1: Default behavior (unwrapped response)
+ async search(query, options = {}) {
+ const paramMappings = {
+ max_results: "maxResults",
+ next_token: "nextToken",
+ "user.fields": "userFields",
+ "tweet.fields": "tweetFields"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
+ const {
+ maxResults = void 0,
+ nextToken = void 0,
+ userFields = [],
+ expansions = [],
+ tweetFields = [],
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/users/search";
+ const params = new URLSearchParams();
+ if (query !== void 0) {
+ params.append("query", String(query));
}
- const normalized = { ...options };
- for (const [originalName, camelName] of Object.entries(paramMappings)) {
- if (originalName in normalized && !(camelName in normalized)) {
- normalized[camelName] = normalized[originalName];
- delete normalized[originalName];
- }
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
}
- return normalized;
+ if (nextToken !== void 0) {
+ params.append("next_token", String(nextToken));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
+ const finalRequestOptions = {
+ // Pass security requirements for smart auth selection
+ security: [
+ {
+ OAuth2UserToken: ["tweet.read", "users.read"]
+ },
+ {
+ UserToken: []
+ }
+ ],
+ ...requestOptions
+ };
+ return this.client.request(
+ "GET",
+ path + (params.toString() ? `?${params.toString()}` : ""),
+ finalRequestOptions
+ );
}
/**
- * Get OpenAPI Spec.
- * Retrieves the full OpenAPI Specification in JSON format. (See https://github.com/OAI/OpenAPI-Specification/blob/master/README.md)
+ * Get User by ID
+ * Retrieves details of a specific User by their ID.
+
+ * @param id The ID of the User to lookup.
- * @returns {Promise} Promise resolving to the API response
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getOpenApiSpec() {
- let path = "/2/openapi.json";
+ async getById(id, options = {}) {
+ const paramMappings = {
+ "user.fields": "userFields",
+ "tweet.fields": "tweetFields"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
+ const {
+ userFields = [],
+ expansions = [],
+ tweetFields = [],
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/users/{id}";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
const finalRequestOptions = {
- // No optional parameters, using empty request options
+ // Pass security requirements for smart auth selection
+ security: [
+ {
+ BearerToken: []
+ },
+ {
+ OAuth2UserToken: ["tweet.read", "users.read"]
+ },
+ {
+ UserToken: []
+ }
+ ],
+ ...requestOptions
};
return this.client.request(
"GET",
@@ -13367,102 +13313,179 @@ var GeneralClient = class {
finalRequestOptions
);
}
-};
-
-// src/general/models.ts
-var models_exports15 = {};
-
-// src/account_activity/client.ts
-var AccountActivityClient = class {
- client;
- /**
- * Creates a new account activity client instance
- *
- * @param client - The main X API client instance
- */
- constructor(client) {
- this.client = client;
- }
/**
- * Normalize options object to handle both camelCase and original API parameter names
- * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
+ * Get Bookmarks
+ * Retrieves a list of Posts bookmarked by the authenticated user.
+
+
+ * @param id The ID of the authenticated source User for whom to return results.
+
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
- _normalizeOptions(options, paramMappings) {
- if (!options || typeof options !== "object") {
- return options;
+ // Overload 1: Default behavior (unwrapped response)
+ async getBookmarks(id, options = {}) {
+ const paramMappings = {
+ max_results: "maxResults",
+ pagination_token: "paginationToken",
+ "tweet.fields": "tweetFields",
+ "media.fields": "mediaFields",
+ "poll.fields": "pollFields",
+ "user.fields": "userFields",
+ "place.fields": "placeFields"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
+ const {
+ maxResults = void 0,
+ paginationToken = void 0,
+ tweetFields = [],
+ expansions = [],
+ mediaFields = [],
+ pollFields = [],
+ userFields = [],
+ placeFields = [],
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/users/{id}/bookmarks";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
+ const params = new URLSearchParams();
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
}
- const normalized = { ...options };
- for (const [originalName, camelName] of Object.entries(paramMappings)) {
- if (originalName in normalized && !(camelName in normalized)) {
- normalized[camelName] = normalized[originalName];
- delete normalized[originalName];
- }
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
}
- return normalized;
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (mediaFields !== void 0 && mediaFields.length > 0) {
+ params.append("media.fields", mediaFields.join(","));
+ }
+ if (pollFields !== void 0 && pollFields.length > 0) {
+ params.append("poll.fields", pollFields.join(","));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (placeFields !== void 0 && placeFields.length > 0) {
+ params.append("place.fields", placeFields.join(","));
+ }
+ const finalRequestOptions = {
+ // Pass security requirements for smart auth selection
+ security: [
+ {
+ OAuth2UserToken: ["bookmark.read", "tweet.read", "users.read"]
+ }
+ ],
+ ...requestOptions
+ };
+ return this.client.request(
+ "GET",
+ path + (params.toString() ? `?${params.toString()}` : ""),
+ finalRequestOptions
+ );
}
/**
- * Validate subscription
- * Checks a user’s Account Activity subscription for a given webhook.
+ * Create Bookmark
+ * Adds a post to the authenticated user’s bookmarks.
- * @param webhookId The webhook ID to check subscription against.
+ * @param id The ID of the authenticated source User for whom to add bookmarks.
- * @returns {Promise} Promise resolving to the API response
+ * @param body Request body
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async validateSubscription(webhookId) {
- let path = "/2/account_activity/webhooks/{webhook_id}/subscriptions/all";
- path = path.replace("{webhook_id}", encodeURIComponent(String(webhookId)));
+ async createBookmark(id, body) {
+ let path = "/2/users/{id}/bookmarks";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
const finalRequestOptions = {
+ body: JSON.stringify(body || {}),
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["dm.read", "dm.write", "tweet.read", "users.read"]
- },
- {
- UserToken: []
+ OAuth2UserToken: ["bookmark.write", "tweet.read", "users.read"]
}
]
// No optional parameters, using empty request options
};
return this.client.request(
- "GET",
+ "POST",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Create subscription
- * Creates an Account Activity subscription for the user and the given webhook.
+ * Get followers
+ * Retrieves a list of Users who follow a specific User by their ID.
- * @param webhookId The webhook ID to check subscription against.
+ * @param id The ID of the User to lookup.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async createSubscription(webhookId, options = {}) {
- const normalizedOptions = options || {};
+ async getFollowers(id, options = {}) {
+ const paramMappings = {
+ max_results: "maxResults",
+ pagination_token: "paginationToken",
+ "user.fields": "userFields",
+ "tweet.fields": "tweetFields"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
const {
- body,
+ maxResults = void 0,
+ paginationToken = void 0,
+ userFields = [],
+ expansions = [],
+ tweetFields = [],
requestOptions = {}
} = normalizedOptions;
- let path = "/2/account_activity/webhooks/{webhook_id}/subscriptions/all";
- path = path.replace("{webhook_id}", encodeURIComponent(String(webhookId)));
+ let path = "/2/users/{id}/followers";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
+ }
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
const finalRequestOptions = {
- body: body ? JSON.stringify(body) : void 0,
// Pass security requirements for smart auth selection
security: [
{
- OAuth2UserToken: ["dm.read", "dm.write", "tweet.read", "users.read"]
+ BearerToken: []
+ },
+ {
+ OAuth2UserToken: ["follows.read", "tweet.read", "users.read"]
},
{
UserToken: []
@@ -13471,31 +13494,57 @@ var AccountActivityClient = class {
...requestOptions
};
return this.client.request(
- "POST",
+ "GET",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get subscription count
- * Retrieves a count of currently active Account Activity subscriptions.
+ * Get my User
+ * Retrieves details of the authenticated user.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getSubscriptionCount() {
- let path = "/2/account_activity/subscriptions/count";
+ async getMe(options = {}) {
+ const paramMappings = {
+ "user.fields": "userFields",
+ "tweet.fields": "tweetFields"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
+ const {
+ userFields = [],
+ expansions = [],
+ tweetFields = [],
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/users/me";
const params = new URLSearchParams();
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
+ OAuth2UserToken: ["tweet.read", "users.read"]
+ },
+ {
+ UserToken: []
}
- ]
- // No optional parameters, using empty request options
+ ],
+ ...requestOptions
};
return this.client.request(
"GET",
@@ -13504,124 +13553,206 @@ var AccountActivityClient = class {
);
}
/**
- * Get subscriptions
- * Retrieves a list of all active subscriptions for a given webhook.
+ * Unmute User
+ * Causes the authenticated user to unmute a specific user by their ID.
- * @param webhookId The webhook ID to pull subscriptions for.
+ * @param sourceUserId The ID of the authenticated source User that is requesting to unmute the target User.
+ * @param targetUserId The ID of the User that the source User is requesting to unmute.
- * @returns {Promise} Promise resolving to the API response
+
+
+
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async getSubscriptions(webhookId) {
- let path = "/2/account_activity/webhooks/{webhook_id}/subscriptions/all/list";
- path = path.replace("{webhook_id}", encodeURIComponent(String(webhookId)));
+ async unmuteUser(sourceUserId, targetUserId) {
+ let path = "/2/users/{source_user_id}/muting/{target_user_id}";
+ path = path.replace(
+ "{source_user_id}",
+ encodeURIComponent(String(sourceUserId))
+ );
+ path = path.replace(
+ "{target_user_id}",
+ encodeURIComponent(String(targetUserId))
+ );
const params = new URLSearchParams();
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
+ OAuth2UserToken: ["mute.write", "tweet.read", "users.read"]
+ },
+ {
+ UserToken: []
}
]
// No optional parameters, using empty request options
};
return this.client.request(
- "GET",
+ "DELETE",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
+};
+
+// src/users/models.ts
+var models_exports14 = {};
+
+// src/communities/client.ts
+var CommunitiesClient = class {
+ client;
/**
- * 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.
-
-
- * @param webhookId The unique identifier for the webhook configuration.
-
-
-
-
- * @param fromDate The oldest (starting) UTC timestamp (inclusive) from which events will be provided, in `yyyymmddhhmm` format.
+ * Creates a new communities client instance
+ *
+ * @param client - The main X API client instance
+ */
+ constructor(client) {
+ this.client = client;
+ }
+ /**
+ * Normalize options object to handle both camelCase and original API parameter names
+ * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
+ */
+ _normalizeOptions(options, paramMappings) {
+ if (!options || typeof options !== "object") {
+ return options;
+ }
+ const normalized = { ...options };
+ for (const [originalName, camelName] of Object.entries(paramMappings)) {
+ if (originalName in normalized && !(camelName in normalized)) {
+ normalized[camelName] = normalized[originalName];
+ delete normalized[originalName];
+ }
+ }
+ return normalized;
+ }
+ /**
+ * Get Community by ID
+ * Retrieves details of a specific Community by its ID.
+ * @param id The ID of the Community.
- * @param toDate The latest (ending) UTC timestamp (exclusive) up to which events will be provided, in `yyyymmddhhmm` format.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async createReplayJob(webhookId, fromDate, toDate) {
- let path = "/2/account_activity/replay/webhooks/{webhook_id}/subscriptions/all";
- path = path.replace("{webhook_id}", encodeURIComponent(String(webhookId)));
+ async getById(id, options = {}) {
+ const paramMappings = {
+ "community.fields": "communityFields"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
+ const {
+ communityFields = [],
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/communities/{id}";
+ path = path.replace("{id}", encodeURIComponent(String(id)));
const params = new URLSearchParams();
- if (fromDate !== void 0) {
- params.append("from_date", String(fromDate));
- }
- if (toDate !== void 0) {
- params.append("to_date", String(toDate));
+ if (communityFields !== void 0 && communityFields.length > 0) {
+ params.append("community.fields", communityFields.join(","));
}
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
BearerToken: []
+ },
+ {
+ OAuth2UserToken: ["list.read", "tweet.read", "users.read"]
+ },
+ {
+ UserToken: []
}
- ]
- // No optional parameters, using empty request options
+ ],
+ ...requestOptions
};
return this.client.request(
- "POST",
+ "GET",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Delete subscription
- * Deletes an Account Activity subscription for the given webhook and user ID.
-
-
- * @param webhookId The webhook ID to check subscription against.
-
+ * Search Communities
+ * Retrieves a list of Communities matching the specified search query.
- * @param userId User ID to unsubscribe from.
+ * @param query Query to search communities.
- * @returns {Promise} Promise resolving to the API response
+ * @returns {Promise} Promise resolving to the API response
*/
// Overload 1: Default behavior (unwrapped response)
- async deleteSubscription(webhookId, userId) {
- let path = "/2/account_activity/webhooks/{webhook_id}/subscriptions/{user_id}/all";
- path = path.replace("{webhook_id}", encodeURIComponent(String(webhookId)));
- path = path.replace("{user_id}", encodeURIComponent(String(userId)));
+ async search(query, options = {}) {
+ const paramMappings = {
+ max_results: "maxResults",
+ next_token: "nextToken",
+ pagination_token: "paginationToken",
+ "community.fields": "communityFields"
+ };
+ const normalizedOptions = this._normalizeOptions(
+ options || {},
+ paramMappings
+ );
+ const {
+ maxResults = void 0,
+ nextToken = void 0,
+ paginationToken = void 0,
+ communityFields = [],
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/communities/search";
const params = new URLSearchParams();
+ if (query !== void 0) {
+ params.append("query", String(query));
+ }
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
+ }
+ if (nextToken !== void 0) {
+ params.append("next_token", String(nextToken));
+ }
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
+ }
+ if (communityFields !== void 0 && communityFields.length > 0) {
+ params.append("community.fields", communityFields.join(","));
+ }
const finalRequestOptions = {
// Pass security requirements for smart auth selection
security: [
{
- BearerToken: []
+ OAuth2UserToken: ["tweet.read", "users.read"]
+ },
+ {
+ UserToken: []
}
- ]
- // No optional parameters, using empty request options
+ ],
+ ...requestOptions
};
return this.client.request(
- "DELETE",
+ "GET",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
};
-// src/account_activity/models.ts
-var models_exports16 = {};
+// src/communities/models.ts
+var models_exports15 = {};
// src/stream/event_driven_stream.ts
var StreamEvent = {
@@ -13999,8 +14130,8 @@ var StreamClient = class {
return eventStream;
}
/**
- * Stream all Posts
- * Streams all public Posts in real-time.
+ * Stream Portuguese Posts
+ * Streams all public Portuguese-language Posts in real-time.
*
* Returns an event-driven stream that's easy to use.
* Use .on() to listen for events like 'data', 'error', 'close'.
@@ -14014,10 +14145,10 @@ var StreamClient = class {
* @returns {Promise} Event-driven stream for handling streaming data
*/
- async postsFirehose(partition, options = {}) {
+ async postsFirehosePt(partition, options = {}) {
const requiredAuthTypes = [];
requiredAuthTypes.push("BearerToken");
- this.client.validateAuthentication(requiredAuthTypes, "postsFirehose");
+ this.client.validateAuthentication(requiredAuthTypes, "postsFirehosePt");
const paramMappings = {
backfill_minutes: "backfillMinutes",
start_time: "startTime",
@@ -14046,7 +14177,7 @@ var StreamClient = class {
signal,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/firehose/stream";
+ let path = "/2/tweets/firehose/stream/lang/pt";
const params = new URLSearchParams();
if (backfillMinutes !== void 0) {
params.append("backfill_minutes", String(backfillMinutes));
@@ -14108,8 +14239,8 @@ var StreamClient = class {
return eventStream;
}
/**
- * Stream Post labels
- * Streams all labeling events applied to Posts.
+ * Stream Japanese Posts
+ * Streams all public Japanese-language Posts in real-time.
*
* Returns an event-driven stream that's easy to use.
* Use .on() to listen for events like 'data', 'error', 'close'.
@@ -14117,16 +14248,25 @@ var StreamClient = class {
+ * @param partition The partition number.
+
+
+
* @returns {Promise} Event-driven stream for handling streaming data
*/
- async labelsCompliance(options = {}) {
+ async postsFirehoseJa(partition, options = {}) {
const requiredAuthTypes = [];
requiredAuthTypes.push("BearerToken");
- this.client.validateAuthentication(requiredAuthTypes, "labelsCompliance");
+ this.client.validateAuthentication(requiredAuthTypes, "postsFirehoseJa");
const paramMappings = {
backfill_minutes: "backfillMinutes",
start_time: "startTime",
- end_time: "endTime"
+ end_time: "endTime",
+ "tweet.fields": "tweetFields",
+ "media.fields": "mediaFields",
+ "poll.fields": "pollFields",
+ "user.fields": "userFields",
+ "place.fields": "placeFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
@@ -14136,21 +14276,48 @@ var StreamClient = class {
backfillMinutes = void 0,
startTime = void 0,
endTime = void 0,
+ tweetFields = [],
+ expansions = [],
+ mediaFields = [],
+ pollFields = [],
+ userFields = [],
+ placeFields = [],
headers = {},
signal,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/label/stream";
+ let path = "/2/tweets/firehose/stream/lang/ja";
const params = new URLSearchParams();
if (backfillMinutes !== void 0) {
params.append("backfill_minutes", String(backfillMinutes));
}
+ if (partition !== void 0) {
+ params.append("partition", String(partition));
+ }
if (startTime !== void 0) {
params.append("start_time", String(startTime));
}
if (endTime !== void 0) {
params.append("end_time", String(endTime));
}
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (mediaFields !== void 0 && mediaFields.length > 0) {
+ params.append("media.fields", mediaFields.join(","));
+ }
+ if (pollFields !== void 0 && pollFields.length > 0) {
+ params.append("poll.fields", pollFields.join(","));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (placeFields !== void 0 && placeFields.length > 0) {
+ params.append("place.fields", placeFields.join(","));
+ }
const url = path + (params.toString() ? `?${params.toString()}` : "");
const response = await this.client.request("GET", url, {
headers: {
@@ -14181,8 +14348,8 @@ var StreamClient = class {
return eventStream;
}
/**
- * Stream Likes compliance data
- * Streams all compliance data related to Likes for Users.
+ * Stream 10% sampled Posts
+ * Streams a 10% sample of public Posts in real-time.
*
* Returns an event-driven stream that's easy to use.
* Use .on() to listen for events like 'data', 'error', 'close'.
@@ -14190,16 +14357,25 @@ var StreamClient = class {
+ * @param partition The partition number.
+
+
+
* @returns {Promise} Event-driven stream for handling streaming data
*/
- async likesCompliance(options = {}) {
+ async postsSample10(partition, options = {}) {
const requiredAuthTypes = [];
requiredAuthTypes.push("BearerToken");
- this.client.validateAuthentication(requiredAuthTypes, "likesCompliance");
+ this.client.validateAuthentication(requiredAuthTypes, "postsSample10");
const paramMappings = {
backfill_minutes: "backfillMinutes",
start_time: "startTime",
- end_time: "endTime"
+ end_time: "endTime",
+ "tweet.fields": "tweetFields",
+ "media.fields": "mediaFields",
+ "poll.fields": "pollFields",
+ "user.fields": "userFields",
+ "place.fields": "placeFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
@@ -14209,21 +14385,48 @@ var StreamClient = class {
backfillMinutes = void 0,
startTime = void 0,
endTime = void 0,
+ tweetFields = [],
+ expansions = [],
+ mediaFields = [],
+ pollFields = [],
+ userFields = [],
+ placeFields = [],
headers = {},
signal,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/likes/compliance/stream";
+ let path = "/2/tweets/sample10/stream";
const params = new URLSearchParams();
if (backfillMinutes !== void 0) {
params.append("backfill_minutes", String(backfillMinutes));
}
+ if (partition !== void 0) {
+ params.append("partition", String(partition));
+ }
if (startTime !== void 0) {
params.append("start_time", String(startTime));
}
if (endTime !== void 0) {
params.append("end_time", String(endTime));
}
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (mediaFields !== void 0 && mediaFields.length > 0) {
+ params.append("media.fields", mediaFields.join(","));
+ }
+ if (pollFields !== void 0 && pollFields.length > 0) {
+ params.append("poll.fields", pollFields.join(","));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (placeFields !== void 0 && placeFields.length > 0) {
+ params.append("place.fields", placeFields.join(","));
+ }
const url = path + (params.toString() ? `?${params.toString()}` : "");
const response = await this.client.request("GET", url, {
headers: {
@@ -14254,8 +14457,8 @@ var StreamClient = class {
return eventStream;
}
/**
- * 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.
*
* Returns an event-driven stream that's easy to use.
* Use .on() to listen for events like 'data', 'error', 'close'.
@@ -14269,17 +14472,19 @@ var StreamClient = class {
* @returns {Promise} Event-driven stream for handling streaming data
*/
- async likesSample10(partition, options = {}) {
+ async postsFirehoseKo(partition, options = {}) {
const requiredAuthTypes = [];
requiredAuthTypes.push("BearerToken");
- this.client.validateAuthentication(requiredAuthTypes, "likesSample10");
+ this.client.validateAuthentication(requiredAuthTypes, "postsFirehoseKo");
const paramMappings = {
backfill_minutes: "backfillMinutes",
start_time: "startTime",
end_time: "endTime",
- "like_with_tweet_author.fields": "likeWithTweetAuthorFields",
+ "tweet.fields": "tweetFields",
+ "media.fields": "mediaFields",
+ "poll.fields": "pollFields",
"user.fields": "userFields",
- "tweet.fields": "tweetFields"
+ "place.fields": "placeFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
@@ -14289,15 +14494,17 @@ var StreamClient = class {
backfillMinutes = void 0,
startTime = void 0,
endTime = void 0,
- likeWithTweetAuthorFields = [],
+ tweetFields = [],
expansions = [],
+ mediaFields = [],
+ pollFields = [],
userFields = [],
- tweetFields = [],
+ placeFields = [],
headers = {},
signal,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/likes/sample10/stream";
+ let path = "/2/tweets/firehose/stream/lang/ko";
const params = new URLSearchParams();
if (backfillMinutes !== void 0) {
params.append("backfill_minutes", String(backfillMinutes));
@@ -14311,20 +14518,23 @@ var StreamClient = class {
if (endTime !== void 0) {
params.append("end_time", String(endTime));
}
- if (likeWithTweetAuthorFields !== void 0 && likeWithTweetAuthorFields.length > 0) {
- params.append(
- "like_with_tweet_author.fields",
- likeWithTweetAuthorFields.join(",")
- );
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
}
if (expansions !== void 0 && expansions.length > 0) {
params.append("expansions", expansions.join(","));
}
+ if (mediaFields !== void 0 && mediaFields.length > 0) {
+ params.append("media.fields", mediaFields.join(","));
+ }
+ if (pollFields !== void 0 && pollFields.length > 0) {
+ params.append("poll.fields", pollFields.join(","));
+ }
if (userFields !== void 0 && userFields.length > 0) {
params.append("user.fields", userFields.join(","));
}
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ if (placeFields !== void 0 && placeFields.length > 0) {
+ params.append("place.fields", placeFields.join(","));
}
const url = path + (params.toString() ? `?${params.toString()}` : "");
const response = await this.client.request("GET", url, {
@@ -14356,8 +14566,8 @@ var StreamClient = class {
return eventStream;
}
/**
- * Stream Portuguese Posts
- * Streams all public Portuguese-language Posts in real-time.
+ * Stream Likes compliance data
+ * Streams all compliance data related to Likes for Users.
*
* Returns an event-driven stream that's easy to use.
* Use .on() to listen for events like 'data', 'error', 'close'.
@@ -14365,25 +14575,16 @@ var StreamClient = class {
- * @param partition The partition number.
-
-
-
* @returns {Promise} Event-driven stream for handling streaming data
*/
- async postsFirehosePt(partition, options = {}) {
+ async likesCompliance(options = {}) {
const requiredAuthTypes = [];
requiredAuthTypes.push("BearerToken");
- this.client.validateAuthentication(requiredAuthTypes, "postsFirehosePt");
+ this.client.validateAuthentication(requiredAuthTypes, "likesCompliance");
const paramMappings = {
backfill_minutes: "backfillMinutes",
start_time: "startTime",
- end_time: "endTime",
- "tweet.fields": "tweetFields",
- "media.fields": "mediaFields",
- "poll.fields": "pollFields",
- "user.fields": "userFields",
- "place.fields": "placeFields"
+ end_time: "endTime"
};
const normalizedOptions = this._normalizeOptions(
options || {},
@@ -14392,48 +14593,21 @@ var StreamClient = class {
const {
backfillMinutes = void 0,
startTime = void 0,
- endTime = void 0,
- tweetFields = [],
- expansions = [],
- mediaFields = [],
- pollFields = [],
- userFields = [],
- placeFields = [],
- headers = {},
- signal,
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/tweets/firehose/stream/lang/pt";
- const params = new URLSearchParams();
- if (backfillMinutes !== void 0) {
- params.append("backfill_minutes", String(backfillMinutes));
- }
- if (partition !== void 0) {
- params.append("partition", String(partition));
- }
- if (startTime !== void 0) {
- params.append("start_time", String(startTime));
- }
- if (endTime !== void 0) {
- params.append("end_time", String(endTime));
- }
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (mediaFields !== void 0 && mediaFields.length > 0) {
- params.append("media.fields", mediaFields.join(","));
- }
- if (pollFields !== void 0 && pollFields.length > 0) {
- params.append("poll.fields", pollFields.join(","));
+ endTime = void 0,
+ headers = {},
+ signal,
+ requestOptions = {}
+ } = normalizedOptions;
+ let path = "/2/likes/compliance/stream";
+ const params = new URLSearchParams();
+ if (backfillMinutes !== void 0) {
+ params.append("backfill_minutes", String(backfillMinutes));
}
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
+ if (startTime !== void 0) {
+ params.append("start_time", String(startTime));
}
- if (placeFields !== void 0 && placeFields.length > 0) {
- params.append("place.fields", placeFields.join(","));
+ if (endTime !== void 0) {
+ params.append("end_time", String(endTime));
}
const url = path + (params.toString() ? `?${params.toString()}` : "");
const response = await this.client.request("GET", url, {
@@ -14465,8 +14639,8 @@ var StreamClient = class {
return eventStream;
}
/**
- * Stream English Posts
- * Streams all public English-language Posts in real-time.
+ * Stream Posts compliance data
+ * Streams all compliance data related to Posts.
*
* Returns an event-driven stream that's easy to use.
* Use .on() to listen for events like 'data', 'error', 'close'.
@@ -14480,19 +14654,14 @@ var StreamClient = class {
* @returns {Promise} Event-driven stream for handling streaming data
*/
- async postsFirehoseEn(partition, options = {}) {
+ async postsCompliance(partition, options = {}) {
const requiredAuthTypes = [];
requiredAuthTypes.push("BearerToken");
- this.client.validateAuthentication(requiredAuthTypes, "postsFirehoseEn");
+ this.client.validateAuthentication(requiredAuthTypes, "postsCompliance");
const paramMappings = {
backfill_minutes: "backfillMinutes",
start_time: "startTime",
- end_time: "endTime",
- "tweet.fields": "tweetFields",
- "media.fields": "mediaFields",
- "poll.fields": "pollFields",
- "user.fields": "userFields",
- "place.fields": "placeFields"
+ end_time: "endTime"
};
const normalizedOptions = this._normalizeOptions(
options || {},
@@ -14502,17 +14671,11 @@ var StreamClient = class {
backfillMinutes = void 0,
startTime = void 0,
endTime = void 0,
- tweetFields = [],
- expansions = [],
- mediaFields = [],
- pollFields = [],
- userFields = [],
- placeFields = [],
headers = {},
signal,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/firehose/stream/lang/en";
+ let path = "/2/tweets/compliance/stream";
const params = new URLSearchParams();
if (backfillMinutes !== void 0) {
params.append("backfill_minutes", String(backfillMinutes));
@@ -14526,24 +14689,6 @@ var StreamClient = class {
if (endTime !== void 0) {
params.append("end_time", String(endTime));
}
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (mediaFields !== void 0 && mediaFields.length > 0) {
- params.append("media.fields", mediaFields.join(","));
- }
- if (pollFields !== void 0 && pollFields.length > 0) {
- params.append("poll.fields", pollFields.join(","));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (placeFields !== void 0 && placeFields.length > 0) {
- params.append("place.fields", placeFields.join(","));
- }
const url = path + (params.toString() ? `?${params.toString()}` : "");
const response = await this.client.request("GET", url, {
headers: {
@@ -14574,8 +14719,8 @@ var StreamClient = class {
return eventStream;
}
/**
- * Stream filtered Posts
- * Streams Posts in real-time matching the active rule set.
+ * Stream all Likes
+ * Streams all public Likes in real-time.
*
* Returns an event-driven stream that's easy to use.
* Use .on() to listen for events like 'data', 'error', 'close'.
@@ -14583,21 +14728,23 @@ var StreamClient = class {
+ * @param partition The partition number.
+
+
+
* @returns {Promise} Event-driven stream for handling streaming data
*/
- async posts(options = {}) {
+ async likesFirehose(partition, options = {}) {
const requiredAuthTypes = [];
requiredAuthTypes.push("BearerToken");
- this.client.validateAuthentication(requiredAuthTypes, "posts");
+ this.client.validateAuthentication(requiredAuthTypes, "likesFirehose");
const paramMappings = {
backfill_minutes: "backfillMinutes",
start_time: "startTime",
end_time: "endTime",
- "tweet.fields": "tweetFields",
- "media.fields": "mediaFields",
- "poll.fields": "pollFields",
+ "like_with_tweet_author.fields": "likeWithTweetAuthorFields",
"user.fields": "userFields",
- "place.fields": "placeFields"
+ "tweet.fields": "tweetFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
@@ -14607,44 +14754,42 @@ var StreamClient = class {
backfillMinutes = void 0,
startTime = void 0,
endTime = void 0,
- tweetFields = [],
+ likeWithTweetAuthorFields = [],
expansions = [],
- mediaFields = [],
- pollFields = [],
userFields = [],
- placeFields = [],
+ tweetFields = [],
headers = {},
signal,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/search/stream";
+ let path = "/2/likes/firehose/stream";
const params = new URLSearchParams();
if (backfillMinutes !== void 0) {
params.append("backfill_minutes", String(backfillMinutes));
}
+ if (partition !== void 0) {
+ params.append("partition", String(partition));
+ }
if (startTime !== void 0) {
params.append("start_time", String(startTime));
}
if (endTime !== void 0) {
params.append("end_time", String(endTime));
}
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ if (likeWithTweetAuthorFields !== void 0 && likeWithTweetAuthorFields.length > 0) {
+ params.append(
+ "like_with_tweet_author.fields",
+ likeWithTweetAuthorFields.join(",")
+ );
}
if (expansions !== void 0 && expansions.length > 0) {
params.append("expansions", expansions.join(","));
}
- if (mediaFields !== void 0 && mediaFields.length > 0) {
- params.append("media.fields", mediaFields.join(","));
- }
- if (pollFields !== void 0 && pollFields.length > 0) {
- params.append("poll.fields", pollFields.join(","));
- }
if (userFields !== void 0 && userFields.length > 0) {
params.append("user.fields", userFields.join(","));
}
- if (placeFields !== void 0 && placeFields.length > 0) {
- params.append("place.fields", placeFields.join(","));
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
}
const url = path + (params.toString() ? `?${params.toString()}` : "");
const response = await this.client.request("GET", url, {
@@ -14676,8 +14821,8 @@ var StreamClient = class {
return eventStream;
}
/**
- * Stream Posts compliance data
- * Streams all compliance data related to Posts.
+ * Stream English Posts
+ * Streams all public English-language Posts in real-time.
*
* Returns an event-driven stream that's easy to use.
* Use .on() to listen for events like 'data', 'error', 'close'.
@@ -14691,14 +14836,19 @@ var StreamClient = class {
* @returns {Promise} Event-driven stream for handling streaming data
*/
- async postsCompliance(partition, options = {}) {
+ async postsFirehoseEn(partition, options = {}) {
const requiredAuthTypes = [];
requiredAuthTypes.push("BearerToken");
- this.client.validateAuthentication(requiredAuthTypes, "postsCompliance");
+ this.client.validateAuthentication(requiredAuthTypes, "postsFirehoseEn");
const paramMappings = {
backfill_minutes: "backfillMinutes",
start_time: "startTime",
- end_time: "endTime"
+ end_time: "endTime",
+ "tweet.fields": "tweetFields",
+ "media.fields": "mediaFields",
+ "poll.fields": "pollFields",
+ "user.fields": "userFields",
+ "place.fields": "placeFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
@@ -14708,11 +14858,17 @@ var StreamClient = class {
backfillMinutes = void 0,
startTime = void 0,
endTime = void 0,
+ tweetFields = [],
+ expansions = [],
+ mediaFields = [],
+ pollFields = [],
+ userFields = [],
+ placeFields = [],
headers = {},
signal,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/compliance/stream";
+ let path = "/2/tweets/firehose/stream/lang/en";
const params = new URLSearchParams();
if (backfillMinutes !== void 0) {
params.append("backfill_minutes", String(backfillMinutes));
@@ -14726,6 +14882,24 @@ var StreamClient = class {
if (endTime !== void 0) {
params.append("end_time", String(endTime));
}
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
+ }
+ if (expansions !== void 0 && expansions.length > 0) {
+ params.append("expansions", expansions.join(","));
+ }
+ if (mediaFields !== void 0 && mediaFields.length > 0) {
+ params.append("media.fields", mediaFields.join(","));
+ }
+ if (pollFields !== void 0 && pollFields.length > 0) {
+ params.append("poll.fields", pollFields.join(","));
+ }
+ if (userFields !== void 0 && userFields.length > 0) {
+ params.append("user.fields", userFields.join(","));
+ }
+ if (placeFields !== void 0 && placeFields.length > 0) {
+ params.append("place.fields", placeFields.join(","));
+ }
const url = path + (params.toString() ? `?${params.toString()}` : "");
const response = await this.client.request("GET", url, {
headers: {
@@ -14756,8 +14930,8 @@ var StreamClient = class {
return eventStream;
}
/**
- * Stream Korean Posts
- * Streams all public Korean-language Posts in real-time.
+ * Stream filtered Posts
+ * Streams Posts in real-time matching the active rule set.
*
* Returns an event-driven stream that's easy to use.
* Use .on() to listen for events like 'data', 'error', 'close'.
@@ -14765,16 +14939,12 @@ var StreamClient = class {
- * @param partition The partition number.
-
-
-
* @returns {Promise} Event-driven stream for handling streaming data
*/
- async postsFirehoseKo(partition, options = {}) {
+ async posts(options = {}) {
const requiredAuthTypes = [];
requiredAuthTypes.push("BearerToken");
- this.client.validateAuthentication(requiredAuthTypes, "postsFirehoseKo");
+ this.client.validateAuthentication(requiredAuthTypes, "posts");
const paramMappings = {
backfill_minutes: "backfillMinutes",
start_time: "startTime",
@@ -14803,14 +14973,11 @@ var StreamClient = class {
signal,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/firehose/stream/lang/ko";
+ let path = "/2/tweets/search/stream";
const params = new URLSearchParams();
if (backfillMinutes !== void 0) {
params.append("backfill_minutes", String(backfillMinutes));
}
- if (partition !== void 0) {
- params.append("partition", String(partition));
- }
if (startTime !== void 0) {
params.append("start_time", String(startTime));
}
@@ -14865,8 +15032,8 @@ var StreamClient = class {
return eventStream;
}
/**
- * Stream all Likes
- * Streams all public Likes in real-time.
+ * Stream Users compliance data
+ * Streams all compliance data related to Users.
*
* Returns an event-driven stream that's easy to use.
* Use .on() to listen for events like 'data', 'error', 'close'.
@@ -14880,17 +15047,14 @@ var StreamClient = class {
* @returns {Promise} Event-driven stream for handling streaming data
*/
- async likesFirehose(partition, options = {}) {
+ async usersCompliance(partition, options = {}) {
const requiredAuthTypes = [];
requiredAuthTypes.push("BearerToken");
- this.client.validateAuthentication(requiredAuthTypes, "likesFirehose");
+ this.client.validateAuthentication(requiredAuthTypes, "usersCompliance");
const paramMappings = {
backfill_minutes: "backfillMinutes",
start_time: "startTime",
- end_time: "endTime",
- "like_with_tweet_author.fields": "likeWithTweetAuthorFields",
- "user.fields": "userFields",
- "tweet.fields": "tweetFields"
+ end_time: "endTime"
};
const normalizedOptions = this._normalizeOptions(
options || {},
@@ -14900,15 +15064,11 @@ var StreamClient = class {
backfillMinutes = void 0,
startTime = void 0,
endTime = void 0,
- likeWithTweetAuthorFields = [],
- expansions = [],
- userFields = [],
- tweetFields = [],
headers = {},
signal,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/likes/firehose/stream";
+ let path = "/2/users/compliance/stream";
const params = new URLSearchParams();
if (backfillMinutes !== void 0) {
params.append("backfill_minutes", String(backfillMinutes));
@@ -14922,21 +15082,6 @@ var StreamClient = class {
if (endTime !== void 0) {
params.append("end_time", String(endTime));
}
- if (likeWithTweetAuthorFields !== void 0 && likeWithTweetAuthorFields.length > 0) {
- params.append(
- "like_with_tweet_author.fields",
- likeWithTweetAuthorFields.join(",")
- );
- }
- if (expansions !== void 0 && expansions.length > 0) {
- params.append("expansions", expansions.join(","));
- }
- if (userFields !== void 0 && userFields.length > 0) {
- params.append("user.fields", userFields.join(","));
- }
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
- }
const url = path + (params.toString() ? `?${params.toString()}` : "");
const response = await this.client.request("GET", url, {
headers: {
@@ -14967,8 +15112,8 @@ var StreamClient = class {
return eventStream;
}
/**
- * Stream 10% sampled Posts
- * Streams a 10% sample of public Posts in real-time.
+ * Stream all Posts
+ * Streams all public Posts in real-time.
*
* Returns an event-driven stream that's easy to use.
* Use .on() to listen for events like 'data', 'error', 'close'.
@@ -14982,10 +15127,10 @@ var StreamClient = class {
* @returns {Promise} Event-driven stream for handling streaming data
*/
- async postsSample10(partition, options = {}) {
+ async postsFirehose(partition, options = {}) {
const requiredAuthTypes = [];
requiredAuthTypes.push("BearerToken");
- this.client.validateAuthentication(requiredAuthTypes, "postsSample10");
+ this.client.validateAuthentication(requiredAuthTypes, "postsFirehose");
const paramMappings = {
backfill_minutes: "backfillMinutes",
start_time: "startTime",
@@ -15014,7 +15159,7 @@ var StreamClient = class {
signal,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/sample10/stream";
+ let path = "/2/tweets/firehose/stream";
const params = new URLSearchParams();
if (backfillMinutes !== void 0) {
params.append("backfill_minutes", String(backfillMinutes));
@@ -15076,8 +15221,8 @@ var StreamClient = class {
return eventStream;
}
/**
- * Stream Japanese Posts
- * Streams all public Japanese-language Posts in real-time.
+ * Stream sampled Likes
+ * Streams a 10% sample of public Likes in real-time.
*
* Returns an event-driven stream that's easy to use.
* Use .on() to listen for events like 'data', 'error', 'close'.
@@ -15091,19 +15236,17 @@ var StreamClient = class {
* @returns {Promise} Event-driven stream for handling streaming data
*/
- async postsFirehoseJa(partition, options = {}) {
+ async likesSample10(partition, options = {}) {
const requiredAuthTypes = [];
requiredAuthTypes.push("BearerToken");
- this.client.validateAuthentication(requiredAuthTypes, "postsFirehoseJa");
+ this.client.validateAuthentication(requiredAuthTypes, "likesSample10");
const paramMappings = {
backfill_minutes: "backfillMinutes",
start_time: "startTime",
end_time: "endTime",
- "tweet.fields": "tweetFields",
- "media.fields": "mediaFields",
- "poll.fields": "pollFields",
+ "like_with_tweet_author.fields": "likeWithTweetAuthorFields",
"user.fields": "userFields",
- "place.fields": "placeFields"
+ "tweet.fields": "tweetFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
@@ -15113,17 +15256,15 @@ var StreamClient = class {
backfillMinutes = void 0,
startTime = void 0,
endTime = void 0,
- tweetFields = [],
+ likeWithTweetAuthorFields = [],
expansions = [],
- mediaFields = [],
- pollFields = [],
userFields = [],
- placeFields = [],
+ tweetFields = [],
headers = {},
signal,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/firehose/stream/lang/ja";
+ let path = "/2/likes/sample10/stream";
const params = new URLSearchParams();
if (backfillMinutes !== void 0) {
params.append("backfill_minutes", String(backfillMinutes));
@@ -15137,23 +15278,20 @@ var StreamClient = class {
if (endTime !== void 0) {
params.append("end_time", String(endTime));
}
- if (tweetFields !== void 0 && tweetFields.length > 0) {
- params.append("tweet.fields", tweetFields.join(","));
+ if (likeWithTweetAuthorFields !== void 0 && likeWithTweetAuthorFields.length > 0) {
+ params.append(
+ "like_with_tweet_author.fields",
+ likeWithTweetAuthorFields.join(",")
+ );
}
if (expansions !== void 0 && expansions.length > 0) {
params.append("expansions", expansions.join(","));
}
- if (mediaFields !== void 0 && mediaFields.length > 0) {
- params.append("media.fields", mediaFields.join(","));
- }
- if (pollFields !== void 0 && pollFields.length > 0) {
- params.append("poll.fields", pollFields.join(","));
- }
if (userFields !== void 0 && userFields.length > 0) {
params.append("user.fields", userFields.join(","));
}
- if (placeFields !== void 0 && placeFields.length > 0) {
- params.append("place.fields", placeFields.join(","));
+ if (tweetFields !== void 0 && tweetFields.length > 0) {
+ params.append("tweet.fields", tweetFields.join(","));
}
const url = path + (params.toString() ? `?${params.toString()}` : "");
const response = await this.client.request("GET", url, {
@@ -15185,8 +15323,8 @@ var StreamClient = class {
return eventStream;
}
/**
- * Stream Users compliance data
- * Streams all compliance data related to Users.
+ * Stream Post labels
+ * Streams all labeling events applied to Posts.
*
* Returns an event-driven stream that's easy to use.
* Use .on() to listen for events like 'data', 'error', 'close'.
@@ -15194,16 +15332,12 @@ var StreamClient = class {
- * @param partition The partition number.
-
-
-
* @returns {Promise} Event-driven stream for handling streaming data
*/
- async usersCompliance(partition, options = {}) {
+ async labelsCompliance(options = {}) {
const requiredAuthTypes = [];
requiredAuthTypes.push("BearerToken");
- this.client.validateAuthentication(requiredAuthTypes, "usersCompliance");
+ this.client.validateAuthentication(requiredAuthTypes, "labelsCompliance");
const paramMappings = {
backfill_minutes: "backfillMinutes",
start_time: "startTime",
@@ -15221,14 +15355,11 @@ var StreamClient = class {
signal,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/users/compliance/stream";
+ let path = "/2/tweets/label/stream";
const params = new URLSearchParams();
if (backfillMinutes !== void 0) {
params.append("backfill_minutes", String(backfillMinutes));
}
- if (partition !== void 0) {
- params.append("partition", String(partition));
- }
if (startTime !== void 0) {
params.append("start_time", String(startTime));
}
@@ -15265,41 +15396,32 @@ var StreamClient = class {
return eventStream;
}
/**
- * Get stream rules
- * Retrieves the active rule set or a subset of rules for the filtered stream.
+ * Get stream rule counts
+ * Retrieves the count of rules in the active rule set for the filtered stream.
*
* @returns Promise with the API response
*/
- async getRules(options = {}) {
+ async getRuleCounts(options = {}) {
const requiredAuthTypes = [];
requiredAuthTypes.push("BearerToken");
- this.client.validateAuthentication(requiredAuthTypes, "getRules");
+ this.client.validateAuthentication(requiredAuthTypes, "getRuleCounts");
const paramMappings = {
- max_results: "maxResults",
- pagination_token: "paginationToken"
+ "rules_count.fields": "rulesCountFields"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- ids = [],
- maxResults = void 0,
- paginationToken = void 0,
+ rulesCountFields = [],
headers = {},
signal,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/search/stream/rules";
+ let path = "/2/tweets/search/stream/rules/counts";
const params = new URLSearchParams();
- if (ids !== void 0 && ids.length > 0) {
- params.append("ids", ids.join(","));
- }
- if (maxResults !== void 0) {
- params.append("max_results", String(maxResults));
- }
- if (paginationToken !== void 0) {
- params.append("pagination_token", String(paginationToken));
+ if (rulesCountFields !== void 0 && rulesCountFields.length > 0) {
+ params.append("rules_count.fields", rulesCountFields.join(","));
}
const finalRequestOptions = {
headers: {
@@ -15316,37 +15438,41 @@ var StreamClient = class {
);
}
/**
- * Update stream rules
- * Adds or deletes rules from the active rule set for the filtered stream.
+ * Get stream rules
+ * Retrieves the active rule set or a subset of rules for the filtered stream.
*
* @returns Promise with the API response
*/
- async updateRules(body, options = {}) {
+ async getRules(options = {}) {
const requiredAuthTypes = [];
requiredAuthTypes.push("BearerToken");
- this.client.validateAuthentication(requiredAuthTypes, "updateRules");
+ this.client.validateAuthentication(requiredAuthTypes, "getRules");
const paramMappings = {
- dry_run: "dryRun",
- delete_all: "deleteAll"
+ max_results: "maxResults",
+ pagination_token: "paginationToken"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- dryRun = void 0,
- deleteAll = void 0,
+ ids = [],
+ maxResults = void 0,
+ paginationToken = void 0,
headers = {},
signal,
requestOptions = {}
} = normalizedOptions;
let path = "/2/tweets/search/stream/rules";
const params = new URLSearchParams();
- if (dryRun !== void 0) {
- params.append("dry_run", String(dryRun));
+ if (ids !== void 0 && ids.length > 0) {
+ params.append("ids", ids.join(","));
}
- if (deleteAll !== void 0) {
- params.append("delete_all", String(deleteAll));
+ if (maxResults !== void 0) {
+ params.append("max_results", String(maxResults));
+ }
+ if (paginationToken !== void 0) {
+ params.append("pagination_token", String(paginationToken));
}
const finalRequestOptions = {
headers: {
@@ -15354,272 +15480,160 @@ var StreamClient = class {
...headers
},
signal,
- body: JSON.stringify(body),
...requestOptions
};
return this.client.request(
- "POST",
+ "GET",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
/**
- * Get stream rule counts
- * Retrieves the count of rules in the active rule set for the filtered stream.
+ * Update stream rules
+ * Adds or deletes rules from the active rule set for the filtered stream.
*
* @returns Promise with the API response
*/
- async getRuleCounts(options = {}) {
+ async updateRules(body, options = {}) {
const requiredAuthTypes = [];
requiredAuthTypes.push("BearerToken");
- this.client.validateAuthentication(requiredAuthTypes, "getRuleCounts");
+ this.client.validateAuthentication(requiredAuthTypes, "updateRules");
const paramMappings = {
- "rules_count.fields": "rulesCountFields"
+ dry_run: "dryRun",
+ delete_all: "deleteAll"
};
const normalizedOptions = this._normalizeOptions(
options || {},
paramMappings
);
const {
- rulesCountFields = [],
+ dryRun = void 0,
+ deleteAll = void 0,
headers = {},
signal,
requestOptions = {}
} = normalizedOptions;
- let path = "/2/tweets/search/stream/rules/counts";
+ let path = "/2/tweets/search/stream/rules";
const params = new URLSearchParams();
- if (rulesCountFields !== void 0 && rulesCountFields.length > 0) {
- params.append("rules_count.fields", rulesCountFields.join(","));
+ if (dryRun !== void 0) {
+ params.append("dry_run", String(dryRun));
+ }
+ if (deleteAll !== void 0) {
+ params.append("delete_all", String(deleteAll));
}
const finalRequestOptions = {
headers: {
"Content-Type": "application/json",
...headers
},
- signal,
- ...requestOptions
- };
- return this.client.request(
- "GET",
- path + (params.toString() ? `?${params.toString()}` : ""),
- finalRequestOptions
- );
- }
-};
-
-// src/webhooks/client.ts
-var WebhooksClient = class {
- client;
- /**
- * Creates a new webhooks client instance
- *
- * @param client - The main X API client instance
- */
- constructor(client) {
- this.client = client;
- }
- /**
- * Normalize options object to handle both camelCase and original API parameter names
- * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
- */
- _normalizeOptions(options, paramMappings) {
- if (!options || typeof options !== "object") {
- return options;
- }
- const normalized = { ...options };
- for (const [originalName, camelName] of Object.entries(paramMappings)) {
- if (originalName in normalized && !(camelName in normalized)) {
- normalized[camelName] = normalized[originalName];
- delete normalized[originalName];
- }
- }
- return normalized;
- }
- /**
- * Create stream link
- * Creates a link to deliver FilteredStream events to the given webhook.
-
-
- * @param webhookId The webhook ID to link to your FilteredStream ruleset.
-
-
-
-
- * @returns {Promise} Promise resolving to the API response
- */
- // Overload 1: Default behavior (unwrapped response)
- async createStreamLink(webhookId, options = {}) {
- const paramMappings = {
- "tweet.fields": "tweetFields",
- "media.fields": "mediaFields",
- "poll.fields": "pollFields",
- "user.fields": "userFields",
- "place.fields": "placeFields"
- };
- const normalizedOptions = this._normalizeOptions(
- options || {},
- paramMappings
- );
- const {
- tweetFields = void 0,
- expansions = void 0,
- mediaFields = void 0,
- pollFields = void 0,
- userFields = void 0,
- placeFields = void 0,
- requestOptions = {}
- } = normalizedOptions;
- let path = "/2/tweets/search/webhooks/{webhook_id}";
- path = path.replace("{webhook_id}", encodeURIComponent(String(webhookId)));
- const params = new URLSearchParams();
- if (tweetFields !== void 0) {
- params.append("tweet.fields", String(tweetFields));
- }
- if (expansions !== void 0) {
- params.append("expansions", String(expansions));
- }
- if (mediaFields !== void 0) {
- params.append("media.fields", String(mediaFields));
- }
- if (pollFields !== void 0) {
- params.append("poll.fields", String(pollFields));
- }
- if (userFields !== void 0) {
- params.append("user.fields", String(userFields));
- }
- if (placeFields !== void 0) {
- params.append("place.fields", String(placeFields));
- }
- const finalRequestOptions = {
- // Pass security requirements for smart auth selection
- security: [
- {
- BearerToken: []
- }
- ],
- ...requestOptions
- };
- return this.client.request(
- "POST",
- path + (params.toString() ? `?${params.toString()}` : ""),
- finalRequestOptions
- );
- }
- /**
- * Delete stream link
- * Deletes a link from FilteredStream events to the given webhook.
-
-
- * @param webhookId The webhook ID to link to your FilteredStream ruleset.
-
-
-
-
- * @returns {Promise} Promise resolving to the API response
- */
- // Overload 1: Default behavior (unwrapped response)
- async deleteStreamLink(webhookId) {
- let path = "/2/tweets/search/webhooks/{webhook_id}";
- path = path.replace("{webhook_id}", encodeURIComponent(String(webhookId)));
- const params = new URLSearchParams();
- const finalRequestOptions = {
- // Pass security requirements for smart auth selection
- security: [
- {
- BearerToken: []
- }
- ]
- // No optional parameters, using empty request options
- };
- return this.client.request(
- "DELETE",
- path + (params.toString() ? `?${params.toString()}` : ""),
- finalRequestOptions
- );
- }
- /**
- * Validate webhook
- * Triggers a CRC check for a given webhook.
-
-
- * @param webhookId The ID of the webhook to check.
-
-
-
-
- * @returns {Promise} Promise resolving to the API response
- */
- // Overload 1: Default behavior (unwrapped response)
- async validate(webhookId) {
- let path = "/2/webhooks/{webhook_id}";
- path = path.replace("{webhook_id}", encodeURIComponent(String(webhookId)));
- const params = new URLSearchParams();
- const finalRequestOptions = {
- // Pass security requirements for smart auth selection
- security: [
- {
- BearerToken: []
- },
- {
- UserToken: []
- }
- ]
- // No optional parameters, using empty request options
+ signal,
+ body: JSON.stringify(body),
+ ...requestOptions
};
return this.client.request(
- "PUT",
+ "POST",
path + (params.toString() ? `?${params.toString()}` : ""),
finalRequestOptions
);
}
+};
+
+// src/compliance/client.ts
+var ComplianceClient = class {
+ client;
/**
- * Delete webhook
- * Deletes an existing webhook configuration.
+ * Creates a new compliance client instance
+ *
+ * @param client - The main X API client instance
+ */
+ constructor(client) {
+ this.client = client;
+ }
+ /**
+ * Normalize options object to handle both camelCase and original API parameter names
+ * Only accepts: proper camelCase (tweetFields) and original API format (tweet.fields)
+ */
+ _normalizeOptions(options, paramMappings) {
+ if (!options || typeof options !== "object") {
+ return options;
+ }
+ const normalized = { ...options };
+ for (const [originalName, camelName] of Object.entries(paramMappings)) {
+ if (originalName in normalized && !(camelName in normalized)) {
+ normalized[camelName] = normalized[originalName];
+ delete normalized[originalName];
+ }
+ }
+ return normalized;
+ }
+ /**
+ * Get Compliance Jobs
+ * Retrieves a list of Compliance Jobs filtered by job type and optional status.
- * @param webhookId The ID of the webhook to delete.
+ * @param type Type of Compliance Job to list.
- * @returns {Promise