From b429aa74b2c37d1602dae67bcb7d87a3909dfbc4 Mon Sep 17 00:00:00 2001 From: "P. Raj Kumar" Date: Tue, 12 Mar 2019 09:21:56 -0700 Subject: [PATCH 1/2] Stop sharing class decorators across siblings --- tests/unit/test_builder.py | 4 ++-- uplink/arguments.py | 3 +++ uplink/builder.py | 2 +- uplink/commands.py | 8 ++++++++ uplink/decorators.py | 10 ++++++++-- 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/tests/unit/test_builder.py b/tests/unit/test_builder.py index 6c38ea60..355cbca7 100644 --- a/tests/unit/test_builder.py +++ b/tests/unit/test_builder.py @@ -167,11 +167,11 @@ class Consumer(builder.Consumer): request_method = request_definition_builder # Verify: Get request definition builder on access - assert Consumer.request_method is request_definition_builder + assert Consumer.request_method is request_definition_builder.copy() # Verify: Try again after resetting Consumer.request_method = request_definition_builder - assert Consumer.request_method is request_definition_builder + assert Consumer.request_method is request_definition_builder.copy() # Verify: We get callable on attribute access for an instance consumer = Consumer() diff --git a/uplink/arguments.py b/uplink/arguments.py index 1e7e7e79..979ec53d 100644 --- a/uplink/arguments.py +++ b/uplink/arguments.py @@ -120,6 +120,9 @@ def _process_annotation(self, name, annotation): def is_done(self): return self.remaining_args_count == 0 + def copy(self): + return self + @property def _types(self): types = self._annotations diff --git a/uplink/builder.py b/uplink/builder.py index 34b6fae6..79343197 100644 --- a/uplink/builder.py +++ b/uplink/builder.py @@ -181,7 +181,7 @@ def _build_definition(self): def __get__(self, instance, owner): if instance is None: - return self._request_definition_builder + return self._request_definition_builder.copy() else: return instance.session.create(instance, self._request_definition) diff --git a/uplink/commands.py b/uplink/commands.py index 61b58746..144bd2ad 100644 --- a/uplink/commands.py +++ b/uplink/commands.py @@ -155,6 +155,14 @@ def argument_handler_builder(self): def method_handler_builder(self): return self._method_handler_builder + def copy(self): + return RequestDefinitionBuilder( + self._method, + self._uri, + self._argument_handler_builder.copy(), + self._method_handler_builder.copy(), + ) + def _auto_fill_remaining_arguments(self): uri_vars = set(self.uri.remaining_variables) missing = list(self.argument_handler_builder.missing_arguments) diff --git a/uplink/decorators.py b/uplink/decorators.py index 62574d08..346c1ce5 100644 --- a/uplink/decorators.py +++ b/uplink/decorators.py @@ -37,6 +37,12 @@ def add_annotation(self, annotation, *args_, **kwargs): super(MethodAnnotationHandlerBuilder, self).add_annotation(annotation) return annotation + def copy(self): + clone = MethodAnnotationHandlerBuilder() + clone._class_annotations = list(self._class_annotations) + clone._method_annotations = list(self._method_annotations) + return clone + def build(self): return MethodAnnotationHandler( self._class_annotations + self._method_annotations @@ -89,13 +95,13 @@ def _is_static_call(cls, *args_, **kwargs): else: return is_consumer_class and not (kwargs or args_[1:]) - def __call__(self, class_or_builder): + def __call__(self, class_or_builder, is_class=False): if self._is_consumer_class(class_or_builder): builders = helpers.get_api_definitions(class_or_builder) builders = filter(self._is_relevant_for_builder, builders) for name, b in builders: - b.method_handler_builder.add_annotation(self, is_class=True) + self(b, is_class=True) helpers.set_api_definition(class_or_builder, name, b) elif isinstance(class_or_builder, interfaces.RequestDefinitionBuilder): class_or_builder.method_handler_builder.add_annotation(self) From a85d23a9e99765204a24fb7694ee883725ad248c Mon Sep 17 00:00:00 2001 From: "P. Raj Kumar" Date: Mon, 25 Mar 2019 21:59:08 -0700 Subject: [PATCH 2/2] Fix unit tests --- uplink/decorators.py | 6 ++++-- uplink/interfaces.py | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/uplink/decorators.py b/uplink/decorators.py index 346c1ce5..8db341e1 100644 --- a/uplink/decorators.py +++ b/uplink/decorators.py @@ -95,7 +95,7 @@ def _is_static_call(cls, *args_, **kwargs): else: return is_consumer_class and not (kwargs or args_[1:]) - def __call__(self, class_or_builder, is_class=False): + def __call__(self, class_or_builder, **kwargs): if self._is_consumer_class(class_or_builder): builders = helpers.get_api_definitions(class_or_builder) builders = filter(self._is_relevant_for_builder, builders) @@ -104,7 +104,9 @@ def __call__(self, class_or_builder, is_class=False): self(b, is_class=True) helpers.set_api_definition(class_or_builder, name, b) elif isinstance(class_or_builder, interfaces.RequestDefinitionBuilder): - class_or_builder.method_handler_builder.add_annotation(self) + class_or_builder.method_handler_builder.add_annotation( + self, **kwargs + ) return class_or_builder def modify_request(self, request_builder): diff --git a/uplink/interfaces.py b/uplink/interfaces.py index b87057b2..b610aaf7 100644 --- a/uplink/interfaces.py +++ b/uplink/interfaces.py @@ -99,6 +99,9 @@ def method_handler_builder(self): def build(self): raise NotImplementedError + def copy(self): + raise NotImplementedError + class RequestDefinition(object): def make_converter_registry(self, converters):