Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions xdk-gen/templates/python/client_macros.j2
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ headers = {% if operation.is_streaming %}{
# Stream data chunk by chunk
for chunk in response.iter_content(chunk_size=chunk_size, decode_unicode=True):
if chunk:
# Ensure chunk is always a string, not bytes
if isinstance(chunk, bytes):
chunk = chunk.decode('utf-8')
buffer += chunk

# Process complete lines
Expand Down
4 changes: 2 additions & 2 deletions xdk-gen/templates/python/pyproject_toml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ build-backend = "hatchling.build"

[project]
name = "xdk"
version = "0.1.0"
version = "0.2.1-beta"
description = "Python SDK for the X API"
authors = [
{name = "XDK Team", email = "info@xdk.com"},
{name = "X Developer Platform", email = "twitterdev@x.com"},
]
readme = "README.md"
requires-python = ">=3.8"
Expand Down
4 changes: 2 additions & 2 deletions xdk/python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ build-backend = "hatchling.build"

[project]
name = "xdk"
version = "0.2.0-beta"
version = "0.2.1-beta"
description = "Python SDK for the X API"
authors = [
{name = "X Developer Platform", email = "twitterdev@x.com"},
Expand Down Expand Up @@ -77,4 +77,4 @@ ignore = []
[dependency-groups]
dev = [
"pytest>=8.3.5",
]
]
134 changes: 67 additions & 67 deletions xdk/python/tests/account_activity/test_contracts.py

Large diffs are not rendered by default.

82 changes: 41 additions & 41 deletions xdk/python/tests/account_activity/test_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,35 +25,33 @@ def setup_class(self):
self.account_activity_client = getattr(self.client, "account_activity")


def test_create_replay_job_exists(self):
"""Test that create_replay_job 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, "create_replay_job", None)
method = getattr(AccountActivityClient, "get_subscriptions", None)
assert (
method is not None
), f"Method create_replay_job does not exist on AccountActivityClient"
), f"Method get_subscriptions does not exist on AccountActivityClient"
# Check method is callable
assert callable(method), f"create_replay_job 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"create_replay_job 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 = [
"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 get_subscriptions"
# Check optional parameters have defaults (excluding 'self')
optional_params = []
for optional_param in optional_params:
Expand All @@ -64,14 +62,14 @@ 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_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 create_replay_job should have return type annotation"
), f"Method get_subscriptions should have return type annotation"


def test_delete_subscription_exists(self):
Expand Down Expand Up @@ -216,33 +214,31 @@ def test_create_subscription_return_annotation(self):
), f"Method create_subscription should have return type annotation"


def test_get_subscriptions_exists(self):
"""Test that get_subscriptions 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, "get_subscriptions", None)
method = getattr(AccountActivityClient, "get_subscription_count", None)
assert (
method is not None
), f"Method get_subscriptions does not exist on AccountActivityClient"
), f"Method get_subscription_count does not exist on AccountActivityClient"
# Check method is callable
assert callable(method), f"get_subscriptions 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"get_subscriptions 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 get_subscriptions"
), 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:
Expand All @@ -253,41 +249,45 @@ 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_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 get_subscriptions should have return type annotation"
), f"Method get_subscription_count should have return type annotation"


def test_get_subscription_count_exists(self):
"""Test that get_subscription_count 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, "get_subscription_count", None)
method = getattr(AccountActivityClient, "create_replay_job", None)
assert (
method is not None
), f"Method get_subscription_count does not exist on AccountActivityClient"
), f"Method create_replay_job does not exist on AccountActivityClient"
# Check method is callable
assert callable(method), f"get_subscription_count 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"get_subscription_count 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 = []
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 get_subscription_count"
), 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:
Expand All @@ -298,25 +298,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_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 get_subscription_count should have return type annotation"
), f"Method create_replay_job should have return type annotation"


def test_all_expected_methods_exist(self):
"""Test that all expected methods exist on the client."""
expected_methods = [
"create_replay_job",
"get_subscriptions",
"delete_subscription",
"validate_subscription",
"create_subscription",
"get_subscriptions",
"get_subscription_count",
"create_replay_job",
]
for expected_method in expected_methods:
assert hasattr(
Expand Down
52 changes: 26 additions & 26 deletions xdk/python/tests/communities/test_contracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ def setup_class(self):
self.communities_client = getattr(self.client, "communities")


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()
Expand All @@ -38,11 +38,11 @@ def test_get_by_id_request_structure(self):
# Prepare test parameters
kwargs = {}
# Add required parameters
kwargs["id"] = "test_value"
kwargs["query"] = "test_query"
# Add request body if required
# Call the method
try:
method = getattr(self.communities_client, "get_by_id")
method = getattr(self.communities_client, "search")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
Expand Down Expand Up @@ -77,7 +77,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/communities/{id}"
expected_path = "/2/communities/search"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
Expand All @@ -93,12 +93,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.communities_client, "get_by_id")
def test_search_required_parameters(self):
"""Test that search handles parameters correctly."""
method = getattr(self.communities_client, "search")
# Test with missing required parameters - mock the request to avoid network calls
with patch.object(self.client, "session") as mock_session:
# Mock a 400 response (typical for missing required parameters)
Expand All @@ -112,8 +112,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 = {
Expand All @@ -126,10 +126,10 @@ def test_get_by_id_response_structure(self):
mock_session.get.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
kwargs["id"] = "test"
kwargs["query"] = "test_value"
# Add request body if required
# Call method and verify response structure
method = getattr(self.communities_client, "get_by_id")
method = getattr(self.communities_client, "search")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
Expand All @@ -141,8 +141,8 @@ def test_get_by_id_response_structure(self):
)


def test_search_request_structure(self):
"""Test search 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()
Expand All @@ -155,11 +155,11 @@ def test_search_request_structure(self):
# Prepare test parameters
kwargs = {}
# Add required parameters
kwargs["query"] = "test_query"
kwargs["id"] = "test_value"
# Add request body if required
# Call the method
try:
method = getattr(self.communities_client, "search")
method = getattr(self.communities_client, "get_by_id")
result = method(**kwargs)
# Check if this is a streaming operation (returns Generator)
import types
Expand Down Expand Up @@ -194,7 +194,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/communities/search"
expected_path = "/2/communities/{id}"
assert expected_path.replace("{", "").replace(
"}", ""
) in called_url or any(
Expand All @@ -210,12 +210,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_id: {e}")


def test_search_required_parameters(self):
"""Test that search handles parameters correctly."""
method = getattr(self.communities_client, "search")
def test_get_by_id_required_parameters(self):
"""Test that get_by_id handles parameters correctly."""
method = getattr(self.communities_client, "get_by_id")
# Test with missing required parameters - mock the request to avoid network calls
with patch.object(self.client, "session") as mock_session:
# Mock a 400 response (typical for missing required parameters)
Expand All @@ -229,8 +229,8 @@ def test_search_required_parameters(self):
method()


def test_search_response_structure(self):
"""Test search 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 = {
Expand All @@ -243,10 +243,10 @@ def test_search_response_structure(self):
mock_session.get.return_value = mock_response
# Prepare minimal valid parameters
kwargs = {}
kwargs["query"] = "test_value"
kwargs["id"] = "test"
# Add request body if required
# Call method and verify response structure
method = getattr(self.communities_client, "search")
method = getattr(self.communities_client, "get_by_id")
result = method(**kwargs)
# Verify response object has expected attributes
# Optional field - just check it doesn't cause errors if accessed
Expand Down
Loading