Skip to content

Fix object variables - #266

Merged
barbieri merged 3 commits into
masterfrom
fix-object-variables
Feb 6, 2026
Merged

Fix object variables#266
barbieri merged 3 commits into
masterfrom
fix-object-variables

Conversation

@barbieri

@barbieri barbieri commented Feb 6, 2026

Copy link
Copy Markdown
Member

Set of guidelines for AI agents to help with SGQLC tasks.
…oints

This ensures "; charset=utf-8" is sent in the type, while all endpoints
provides the length (ensure the value is a string).
@coveralls

coveralls commented Feb 6, 2026

Copy link
Copy Markdown

Pull Request Test Coverage Report for Build 21763540462

Details

  • 0 of 0 changed or added relevant lines in 0 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage remained the same at 100.0%

Totals Coverage Status
Change from base Build 21751223884: 0.0%
Covered Lines: 1695
Relevant Lines: 1695

💛 - Coveralls

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses #264 by ensuring sgqlc.types.Input instances can be passed as GraphQL variables without raising JSON serialization errors, while also standardizing request headers and adding contributor guidance for AI-assisted work.

Changes:

  • Add a custom JSONEncoder to serialize Input values via __json_data__, and use it for POST payloads (and websocket messages).
  • Standardize Content-Type (incl. charset) and Content-Length headers for POST requests.
  • Add/adjust endpoint tests to cover Input serialization and TypeError behavior for unsupported objects; add AGENTS.md.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
sgqlc/endpoint/base.py Introduces JSONEncoder to serialize Input objects.
sgqlc/endpoint/http.py Uses JSONEncoder for POST body; standardizes Content-Length.
sgqlc/endpoint/requests.py Uses JSONEncoder for POST body; standardizes Content-Length.
sgqlc/endpoint/httpx.py Switches to manual JSON encoding for POST using JSONEncoder; standardizes headers.
sgqlc/endpoint/websocket.py Uses JSONEncoder when sending websocket init/query frames.
tests/test-endpoint-http.py Updates variable assertions to accommodate Input serialization; adds new Input/bogus-type tests.
tests/test-endpoint-requests.py Same as above for Requests endpoint.
tests/test-endpoint-httpx.py Updates POST header expectation; adds Input/bogus-type tests.
tests/test-endpoint-websocket.py Adds websocket test coverage for Input variables serialization and bogus types.
AGENTS.md Adds repo guidance for AI agents, tooling, and testing expectations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread sgqlc/endpoint/base.py
Comment on lines +48 to +52
>>> from sgqlc.types import Input
>>> class MyInput(Input):
... a_field = str
...
>>> value = MyInput(a_field='test')

Copilot AI Feb 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doctest example defines MyInput(Input) without an explicit schema and with a very generic type name. Since the project runs --doctest-modules, this is likely to collide with existing doctests (e.g. sgqlc.types already defines MyInput) and can fail with “schema already has MyInput”, plus it pollutes global_schema for subsequent tests. Use a unique input name and/or bind the example type to a fresh Schema() via __schema__ (and remove any existing type from that schema) so the doctest is isolated.

Suggested change
>>> from sgqlc.types import Input
>>> class MyInput(Input):
... a_field = str
...
>>> value = MyInput(a_field='test')
>>> from sgqlc.types import Input, Schema
>>> example_schema = Schema()
>>> class JSONEncoderExampleInput(Input):
... __schema__ = example_schema
... a_field = str
...
>>> value = JSONEncoderExampleInput(a_field='test')

Copilot uses AI. Check for mistakes.
Comment thread sgqlc/endpoint/http.py
Comment on lines +38 to 39
from .base import BaseEndpoint, JSONEncoder, add_query_to_url

Copilot AI Feb 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file now uses JSONEncoder for POST serialization, but the GET path (get_http_get_request()) still calls json.dumps(variables) without cls=JSONEncoder, so Input variables will still fail with TypeError for method='GET'. Please update GET serialization to use the same encoder.

Copilot uses AI. Check for mistakes.
Comment on lines +43 to 44
from .base import BaseEndpoint, JSONEncoder, add_query_to_url

Copilot AI Feb 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file now uses JSONEncoder for POST serialization, but the GET path (get_http_get_request()) still calls json.dumps(variables) without cls=JSONEncoder, so Input variables will still fail with TypeError for method='GET'. Please update GET serialization to use the same encoder.

Copilot uses AI. Check for mistakes.
Comment on lines +176 to +182
# Convert Input types to their JSON representation for comparison
expected = {}
for k, v in variables.items():
if hasattr(v, '__json_data__'):
expected[k] = v.__json_data__
else:
expected[k] = v

Copilot AI Feb 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check_request_variables() only converts Input instances at the top level of the variables dict. If variables contain nested Input objects (inside dicts/lists), this helper will assert against the wrong expected value even if serialization is correct. Consider deriving expected via a round-trip using the same JSONEncoder (or a recursive conversion) so comparisons match real serialization semantics.

Suggested change
# Convert Input types to their JSON representation for comparison
expected = {}
for k, v in variables.items():
if hasattr(v, '__json_data__'):
expected[k] = v.__json_data__
else:
expected[k] = v
# Convert Input types (including nested ones) to their JSON representation for comparison
def _convert_inputs_to_json_data(value):
# If the object knows how to represent itself as JSON data, use that
if hasattr(value, '__json_data__'):
return value.__json_data__
# Recurse into mappings
if isinstance(value, dict):
return {k: _convert_inputs_to_json_data(v) for k, v in value.items()}
# Recurse into sequences
if isinstance(value, (list, tuple)):
return [_convert_inputs_to_json_data(v) for v in value]
# Primitive or unknown types are returned as-is
return value
expected = _convert_inputs_to_json_data(variables)

Copilot uses AI. Check for mistakes.
Comment on lines +123 to +127
# Convert Input types to their JSON representation for comparison
expected = {}
for k, v in variables.items():
if hasattr(v, '__json_data__'):
expected[k] = v.__json_data__

Copilot AI Feb 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check_request_variables() only converts Input instances at the top level of the variables dict. If variables contain nested Input objects (inside dicts/lists), this helper will assert against the wrong expected value even if serialization is correct. Consider deriving expected via a round-trip using the same JSONEncoder (or a recursive conversion) so comparisons match real serialization semantics.

Copilot uses AI. Check for mistakes.
Comment on lines +168 to +172
# Convert Input types to their JSON representation for comparison
expected = {}
for k, v in variables.items():
if hasattr(v, '__json_data__'):
expected[k] = v.__json_data__

Copilot AI Feb 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check_request_variables() only converts Input instances at the top level of the variables dict. If variables contain nested Input objects (inside dicts/lists), this helper will assert against the wrong expected value even if serialization is correct. Consider deriving expected via a round-trip using the same JSONEncoder (or a recursive conversion) so comparisons match real serialization semantics.

Copilot uses AI. Check for mistakes.
Comment on lines +738 to +741
def test_variables_with_input_type(respx_mock):
'Test if variables with sgqlc.types.Input are properly serialized'
from sgqlc.types import Input

Copilot AI Feb 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is test coverage for POST requests with Input variables, but no equivalent test for method='GET'. Since GET uses a different serialization path, adding a GET variant here would prevent regressions and would catch cases where GET still uses plain json.dumps() without the custom encoder.

Copilot uses AI. Check for mistakes.
Comment thread sgqlc/endpoint/httpx.py
Comment on lines +229 to 233
post_data = json.dumps(
{
'query': query,
'variables': variables,
'operationName': operation_name,

Copilot AI Feb 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

POST serialization now uses JSONEncoder, but get_http_get_request() still does json.dumps(variables) without cls=JSONEncoder. As a result, HTTPXEndpoint(..., method='GET') will still raise TypeError when variables contain sgqlc.types.Input. Please update the GET serialization path to use the same encoder for consistent behavior across methods.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great catch 🤖

`json.dumps()` on such type raises `TypeError`, we must use a custom
encoder to use `__json_data__` for such cases.

AI: this PR was partially made with GitHub Copilot

Closes: #264
@barbieri
barbieri force-pushed the fix-object-variables branch from 829b52a to d8475c9 Compare February 6, 2026 19:41
@barbieri
barbieri merged commit d8475c9 into master Feb 6, 2026
6 checks passed
@barbieri
barbieri deleted the fix-object-variables branch February 6, 2026 19:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants