From f017a22659fa5b6fa8ad9275b623eadfe8ff0309 Mon Sep 17 00:00:00 2001 From: Jamie Bliss Date: Tue, 17 Mar 2020 13:13:43 -0400 Subject: [PATCH 1/4] Add __dict__ and __weakref__ to all slots --- src/graphql/execution/middleware.py | 2 +- src/graphql/language/ast.py | 6 +++--- src/graphql/language/source.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/graphql/execution/middleware.py b/src/graphql/execution/middleware.py index 334a088a..d75243e6 100644 --- a/src/graphql/execution/middleware.py +++ b/src/graphql/execution/middleware.py @@ -20,7 +20,7 @@ class MiddlewareManager: must be aware of this and check whether values are awaitable before awaiting them. """ - __slots__ = "middlewares", "_middleware_resolvers", "_cached_resolvers" + __slots__ = "__weakref__", "__dict__", "middlewares", "_middleware_resolvers", "_cached_resolvers" _cached_resolvers: Dict[GraphQLFieldResolver, GraphQLFieldResolver] _middleware_resolvers: Optional[List[Callable]] diff --git a/src/graphql/language/ast.py b/src/graphql/language/ast.py index a5da60c6..2cfe40c0 100644 --- a/src/graphql/language/ast.py +++ b/src/graphql/language/ast.py @@ -72,7 +72,7 @@ class Token: Represents a range of characters represented by a lexical token within a Source. """ - __slots__ = ("kind", "start", "end", "line", "column", "prev", "next", "value") + __slots__ = ("__dict__", "__weakref__", "kind", "start", "end", "line", "column", "prev", "next", "value") kind: TokenKind # the kind of token start: int # the character offset at which this Node begins @@ -162,7 +162,7 @@ class Location: region of the source from which the AST derived. """ - __slots__ = ("start", "end", "start_token", "end_token", "source") + __slots__ = ("__dict__", "__weakref__", "start", "end", "start_token", "end_token", "source") start: int # character offset at which this Node begins end: int # character offset at which this Node ends @@ -214,7 +214,7 @@ class OperationType(Enum): class Node: """AST nodes""" - __slots__ = ("loc",) + __slots__ = ("__dict__", "__weakref__", "loc",) loc: Optional[Location] diff --git a/src/graphql/language/source.py b/src/graphql/language/source.py index 9b0e0c42..7f942d93 100644 --- a/src/graphql/language/source.py +++ b/src/graphql/language/source.py @@ -6,7 +6,7 @@ class Source: """A representation of source input to GraphQL.""" - __slots__ = "body", "name", "location_offset" + __slots__ = "__weakref__", "__dict__", "body", "name", "location_offset" def __init__( self, From 0c929b97d0d1857ecb49c38d54df2b9cb6ff86ce Mon Sep 17 00:00:00 2001 From: Jamie Bliss Date: Tue, 17 Mar 2020 13:23:24 -0400 Subject: [PATCH 2/4] Add tests for __weakref__ and __dict__ --- tests/language/test_ast.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/language/test_ast.py b/tests/language/test_ast.py index e9162e98..d63e9195 100644 --- a/tests/language/test_ast.py +++ b/tests/language/test_ast.py @@ -1,4 +1,5 @@ from copy import copy, deepcopy +import weakref from graphql.language import Location, Node, Source, Token, TokenKind from graphql.pyutils import inspect @@ -82,6 +83,16 @@ def can_copy(): assert token2 == token1 assert token2 is not token1 + def can_weakref(): + token = Token(TokenKind.NAME, 1, 2, 1, 2, value="test") + wr = weakref.ref(token) # That this works is 90% of the test + assert wr() is token + + def can_make_attrs(): + token = Token(TokenKind.NAME, 1, 2, 1, 2, value="test") + token.__new_random_attr = "Hello!" # That this works is 90% of the test + assert token.__new_random_attr == "Hello!" + def describe_location_class(): token1 = Token(TokenKind.NAME, 1, 2, 1, 2) @@ -144,6 +155,16 @@ def can_hash(): assert hash(loc4) != hash(loc1) assert hash(loc4) != hash(loc3) + def can_weakref(): + loc = Location(token1, token2, source) + wr = weakref.ref(loc) # That this works is 90% of the test + assert wr() is loc + + def can_make_attrs(): + loc = Location(token1, token2, source) + loc.__new_random_attr = "Hello!" # That this works is 90% of the test + assert loc.__new_random_attr == "Hello!" + def describe_node_class(): def initializes_with_keywords(): @@ -224,3 +245,13 @@ class Foo(Node): def provides_keys_as_class_attribute(): assert SampleTestNode.keys == ["loc", "alpha", "beta"] + + def can_weakref(): + node = SampleTestNode(alpha=1, beta=2) + wr = weakref.ref(node) # That this works is 90% of the test + assert wr() is node + + def can_make_attrs(): + node = SampleTestNode(alpha=1, beta=2) + node.__new_random_attr = "Hello!" # That this works is 90% of the test + assert node.__new_random_attr == "Hello!" From 2376b32f5f8d02b88fb72337be79f2a2d9ad4822 Mon Sep 17 00:00:00 2001 From: Jamie Bliss Date: Tue, 17 Mar 2020 21:36:50 -0400 Subject: [PATCH 3/4] Drop the new dunders on Token and Location This should decrease the memory impact of this PR from +11% to +4%. --- src/graphql/language/ast.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/graphql/language/ast.py b/src/graphql/language/ast.py index 2cfe40c0..74e0c075 100644 --- a/src/graphql/language/ast.py +++ b/src/graphql/language/ast.py @@ -72,7 +72,7 @@ class Token: Represents a range of characters represented by a lexical token within a Source. """ - __slots__ = ("__dict__", "__weakref__", "kind", "start", "end", "line", "column", "prev", "next", "value") + __slots__ = ("kind", "start", "end", "line", "column", "prev", "next", "value") kind: TokenKind # the kind of token start: int # the character offset at which this Node begins @@ -162,7 +162,7 @@ class Location: region of the source from which the AST derived. """ - __slots__ = ("__dict__", "__weakref__", "start", "end", "start_token", "end_token", "source") + __slots__ = ("start", "end", "start_token", "end_token", "source") start: int # character offset at which this Node begins end: int # character offset at which this Node ends From b4ac20b1abda4420144d5b70538d051804e38be3 Mon Sep 17 00:00:00 2001 From: Jamie Bliss Date: Tue, 17 Mar 2020 21:40:17 -0400 Subject: [PATCH 4/4] Remove obsolete tests --- tests/language/test_ast.py | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/tests/language/test_ast.py b/tests/language/test_ast.py index d63e9195..aa965d57 100644 --- a/tests/language/test_ast.py +++ b/tests/language/test_ast.py @@ -83,16 +83,6 @@ def can_copy(): assert token2 == token1 assert token2 is not token1 - def can_weakref(): - token = Token(TokenKind.NAME, 1, 2, 1, 2, value="test") - wr = weakref.ref(token) # That this works is 90% of the test - assert wr() is token - - def can_make_attrs(): - token = Token(TokenKind.NAME, 1, 2, 1, 2, value="test") - token.__new_random_attr = "Hello!" # That this works is 90% of the test - assert token.__new_random_attr == "Hello!" - def describe_location_class(): token1 = Token(TokenKind.NAME, 1, 2, 1, 2) @@ -155,16 +145,6 @@ def can_hash(): assert hash(loc4) != hash(loc1) assert hash(loc4) != hash(loc3) - def can_weakref(): - loc = Location(token1, token2, source) - wr = weakref.ref(loc) # That this works is 90% of the test - assert wr() is loc - - def can_make_attrs(): - loc = Location(token1, token2, source) - loc.__new_random_attr = "Hello!" # That this works is 90% of the test - assert loc.__new_random_attr == "Hello!" - def describe_node_class(): def initializes_with_keywords():