From b94567f8917ceffdeae06e3702e74a5bd476a199 Mon Sep 17 00:00:00 2001 From: Munir Abdinur Date: Thu, 21 Sep 2023 17:27:34 -0400 Subject: [PATCH] fix(graphql): resolves errors raised while parsing graphql asts (#6960) Resolves: https://github.com/DataDog/dd-trace-py/issues/6959 ## Checklist - [x] Change(s) are motivated and described in the PR description. - [x] Testing strategy is described if automated tests are not included in the PR. - [x] Risk is outlined (performance impact, potential for breakage, maintainability, etc). - [x] Change is maintainable (easy to change, telemetry, documentation). - [x] [Library release note guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html) are followed. If no release note is required, add label `changelog/no-changelog`. - [x] Documentation is included (in-code, generated user docs, [public corp docs](https://github.com/DataDog/documentation/)). - [x] Backport labels are set (if [applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)) ## Reviewer Checklist - [ ] Title is accurate. - [ ] No unnecessary changes are introduced. - [ ] Description motivates each change. - [ ] Avoids breaking [API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces) changes unless absolutely necessary. - [ ] Testing strategy adequately addresses listed risk(s). - [ ] Change is maintainable (easy to change, telemetry, documentation). - [ ] Release note makes sense to a user of the library. - [ ] Reviewer has explicitly acknowledged and discussed the performance implications of this PR as reported in the benchmarks PR comment. - [ ] Backport labels are set in a manner that is consistent with the [release branch maintenance policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting) - [ ] If this PR touches code that signs or publishes builds or packages, or handles credentials of any kind, I've requested a review from `@DataDog/security-design-and-guidance`. - [ ] This PR doesn't touch any of that. --------- Co-authored-by: Zachary Groves <32471391+ZStriker19@users.noreply.github.com> (cherry picked from commit e67dcb744d7115370c2751a1082cb988b415bfde) --- ddtrace/contrib/graphql/patch.py | 2 +- ...graphql-document-fix-ef580e19ff2c4db4.yaml | 4 ++ tests/contrib/graphql/test_graphql.py | 8 +++ ...raphql_with_document_with_no_location.json | 55 +++++++++++++++++++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/graphql-document-fix-ef580e19ff2c4db4.yaml create mode 100644 tests/snapshots/tests.contrib.graphql.test_graphql.test_graphql_with_document_with_no_location.json diff --git a/ddtrace/contrib/graphql/patch.py b/ddtrace/contrib/graphql/patch.py index 735d3b7bdb0..f7369b2e40d 100644 --- a/ddtrace/contrib/graphql/patch.py +++ b/ddtrace/contrib/graphql/patch.py @@ -283,7 +283,7 @@ def _get_source_str(obj): source_str = obj elif isinstance(obj, Source): source_str = obj.body - elif isinstance(obj, Document): + elif isinstance(obj, Document) and obj.loc is not None: source_str = obj.loc.source.body else: source_str = "" diff --git a/releasenotes/notes/graphql-document-fix-ef580e19ff2c4db4.yaml b/releasenotes/notes/graphql-document-fix-ef580e19ff2c4db4.yaml new file mode 100644 index 00000000000..1f645234942 --- /dev/null +++ b/releasenotes/notes/graphql-document-fix-ef580e19ff2c4db4.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - | + graphql: Resolves ``AttributeError`` raised while parsing graphql Documents where AST Location is None. diff --git a/tests/contrib/graphql/test_graphql.py b/tests/contrib/graphql/test_graphql.py index 72ffe363e7f..c5ce77f894d 100644 --- a/tests/contrib/graphql/test_graphql.py +++ b/tests/contrib/graphql/test_graphql.py @@ -115,6 +115,14 @@ def test_graphql_v2_with_document(test_schema, test_source_str): assert result.data == {"hello": "friend"} +@snapshot() +def test_graphql_with_document_with_no_location(test_schema, test_source_str): + source = graphql.language.source.Source(test_source_str, "GraphQL request") + document_ast = graphql.language.parser.parse(source, no_location=True) + result = graphql.execute(test_schema, document_ast) + assert result.data == {"hello": "friend"} + + @snapshot(token_override="tests.contrib.graphql.test_graphql.test_graphql") @pytest.mark.skipif(graphql_version < (3, 0), reason="graphql.graphql_sync is NOT suppoerted in v2.0") def test_graphql_sync(test_schema, test_source_str): diff --git a/tests/snapshots/tests.contrib.graphql.test_graphql.test_graphql_with_document_with_no_location.json b/tests/snapshots/tests.contrib.graphql.test_graphql.test_graphql_with_document_with_no_location.json new file mode 100644 index 00000000000..2c9345ccc06 --- /dev/null +++ b/tests/snapshots/tests.contrib.graphql.test_graphql.test_graphql_with_document_with_no_location.json @@ -0,0 +1,55 @@ +[[ + { + "name": "graphql.parse", + "service": "graphql", + "resource": "graphql.parse", + "trace_id": 0, + "span_id": 1, + "parent_id": 0, + "type": "graphql", + "meta": { + "_dd.base_service": "", + "_dd.p.dm": "-0", + "component": "graphql", + "graphql.source": "query HELLO { hello }", + "language": "python", + "runtime-id": "630b203d91914ec1bf98fe21da63344d" + }, + "metrics": { + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "process_id": 29253 + }, + "duration": 284000, + "start": 1695228158961101000 + }], +[ + { + "name": "graphql.execute", + "service": "graphql", + "resource": "graphql.execute", + "trace_id": 1, + "span_id": 1, + "parent_id": 0, + "type": "graphql", + "meta": { + "_dd.base_service": "", + "_dd.p.dm": "-0", + "component": "graphql", + "graphql.operation.name": "HELLO", + "graphql.operation.type": "query", + "graphql.source": "", + "language": "python", + "runtime-id": "630b203d91914ec1bf98fe21da63344d" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1, + "_dd.tracer_kr": 1.0, + "_sampling_priority_v1": 1, + "process_id": 29253 + }, + "duration": 336000, + "start": 1695228158977945000 + }]]