From 03832370c1646ad081f25479a14eb5309dcd87d6 Mon Sep 17 00:00:00 2001 From: Nayan Paavalar Date: Mon, 22 Apr 2024 21:48:44 -0400 Subject: [PATCH 1/7] fixed issue 647 and added test cases --- canvasapi/canvas_object.py | 5 +++-- tests/test_canvas_object.py | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/canvasapi/canvas_object.py b/canvasapi/canvas_object.py index 65d7679f..a3bc3812 100644 --- a/canvasapi/canvas_object.py +++ b/canvasapi/canvas_object.py @@ -59,12 +59,13 @@ def set_attributes(self, attributes): :type attributes: dict """ for attribute, value in attributes.items(): - self.__setattr__(attribute, value) + safe_attribute = attribute.replace("-", "_") + self.__setattr__(safe_attribute, value) try: naive = arrow.get(str(value)).datetime aware = naive.replace(tzinfo=pytz.utc) - naive.utcoffset() - self.__setattr__(attribute + "_date", aware) + self.__setattr__(safe_attribute + "_date", aware) except arrow.ParserError: pass except ValueError: diff --git a/tests/test_canvas_object.py b/tests/test_canvas_object.py index 0a3b176c..feca6700 100644 --- a/tests/test_canvas_object.py +++ b/tests/test_canvas_object.py @@ -52,6 +52,33 @@ def test_set_attributes_valid_date(self, m): self.assertTrue(hasattr(self.canvas_object, "half_offset_date")) self.assertEqual(self.canvas_object.half_offset_date, offset_time) + + # set_attributes with a hyphen + def test_set_attributes_with_hyphens(self, m): + attributes = { + "content-type": "application/json", + "filename": "example.json", + "start-at": "2012-05-05T00:00:00Z", + "end-at": "2012-08-05", + } + + start_date = datetime.strptime( + attributes["start-at"], "%Y-%m-%dT%H:%M:%SZ" + ).replace(tzinfo=pytz.utc) + end_date = datetime.strptime(attributes["end-at"], "%Y-%m-%d").replace( + tzinfo=pytz.utc + ) + + self.canvas_object.set_attributes(attributes) + + self.assertTrue(hasattr(self.canvas_object, "start_at_date")) + self.assertEqual(self.canvas_object.start_at_date, start_date) + self.assertTrue(hasattr(self.canvas_object, "end_at_date")) + self.assertEqual(self.canvas_object.end_at_date, end_date) + self.assertTrue(hasattr(self.canvas_object, "content_type")) + self.assertEqual(self.canvas_object.content_type, "application/json") + self.assertTrue(hasattr(self.canvas_object, "filename")) + self.assertEqual(self.canvas_object.filename, "example.json") def test_set_attributes_invalid_date(self, m): attributes = {"start_at": "2017-01-01T00:00+00:00:00", "end_at": "2012-08-0"} From b087966bb0e257166ae446da06c3b14c79a46557 Mon Sep 17 00:00:00 2001 From: Nayan Paavalar Date: Wed, 24 Apr 2024 05:34:01 -0400 Subject: [PATCH 2/7] changed to keep both attributes and added corresponding tests --- canvasapi/canvas_object.py | 16 +++++++++++--- tests/test_canvas_object.py | 44 ++++++++++++++----------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/canvasapi/canvas_object.py b/canvasapi/canvas_object.py index a3bc3812..78ff891b 100644 --- a/canvasapi/canvas_object.py +++ b/canvasapi/canvas_object.py @@ -1,5 +1,6 @@ import arrow import pytz +import warnings class CanvasObject(object): @@ -59,13 +60,22 @@ def set_attributes(self, attributes): :type attributes: dict """ for attribute, value in attributes.items(): - safe_attribute = attribute.replace("-", "_") - self.__setattr__(safe_attribute, value) + self.__setattr__(attribute, value) + if attribute == "content-type": + self.__setattr__("content_type", value) + warnings.warn( + ( + "The 'content-type' attribute will be removed " + "in a future version. Please use " + "'content_type' instead." + ), + UserWarning, + ) try: naive = arrow.get(str(value)).datetime aware = naive.replace(tzinfo=pytz.utc) - naive.utcoffset() - self.__setattr__(safe_attribute + "_date", aware) + self.__setattr__(attribute + "_date", aware) except arrow.ParserError: pass except ValueError: diff --git a/tests/test_canvas_object.py b/tests/test_canvas_object.py index feca6700..c88f0a3b 100644 --- a/tests/test_canvas_object.py +++ b/tests/test_canvas_object.py @@ -52,33 +52,6 @@ def test_set_attributes_valid_date(self, m): self.assertTrue(hasattr(self.canvas_object, "half_offset_date")) self.assertEqual(self.canvas_object.half_offset_date, offset_time) - - # set_attributes with a hyphen - def test_set_attributes_with_hyphens(self, m): - attributes = { - "content-type": "application/json", - "filename": "example.json", - "start-at": "2012-05-05T00:00:00Z", - "end-at": "2012-08-05", - } - - start_date = datetime.strptime( - attributes["start-at"], "%Y-%m-%dT%H:%M:%SZ" - ).replace(tzinfo=pytz.utc) - end_date = datetime.strptime(attributes["end-at"], "%Y-%m-%d").replace( - tzinfo=pytz.utc - ) - - self.canvas_object.set_attributes(attributes) - - self.assertTrue(hasattr(self.canvas_object, "start_at_date")) - self.assertEqual(self.canvas_object.start_at_date, start_date) - self.assertTrue(hasattr(self.canvas_object, "end_at_date")) - self.assertEqual(self.canvas_object.end_at_date, end_date) - self.assertTrue(hasattr(self.canvas_object, "content_type")) - self.assertEqual(self.canvas_object.content_type, "application/json") - self.assertTrue(hasattr(self.canvas_object, "filename")) - self.assertEqual(self.canvas_object.filename, "example.json") def test_set_attributes_invalid_date(self, m): attributes = {"start_at": "2017-01-01T00:00+00:00:00", "end_at": "2012-08-0"} @@ -89,3 +62,20 @@ def test_set_attributes_invalid_date(self, m): self.assertFalse(hasattr(self.canvas_object, "end_at_date")) self.assertTrue(hasattr(self.canvas_object, "start_at")) self.assertTrue(hasattr(self.canvas_object, "end_at")) + + # set_attributes 'content-type' + def test_set_attributes_with_content_type(self, m): + attributes = { + "content-type": "application/json", + "content_type": "another_application/json", + "filename": "example.json", + } + + self.canvas_object.set_attributes(attributes) + + self.assertTrue(hasattr(self.canvas_object, "content-type")) + self.assertEqual(getattr(self.canvas_object, 'content-type'), "application/json") + self.assertTrue(hasattr(self.canvas_object, "content_type")) + self.assertEqual(self.canvas_object.content_type, "another_application/json") + self.assertTrue(hasattr(self.canvas_object, "filename")) + self.assertEqual(self.canvas_object.filename, "example.json") From ae6c3878f86ebcd24af08a62ff99d786ed30816b Mon Sep 17 00:00:00 2001 From: Nayan Paavalar Date: Wed, 24 Apr 2024 19:07:26 -0400 Subject: [PATCH 3/7] now following correct style implementations for issue #647 --- tests/test_canvas_object.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_canvas_object.py b/tests/test_canvas_object.py index c88f0a3b..859fb8aa 100644 --- a/tests/test_canvas_object.py +++ b/tests/test_canvas_object.py @@ -74,7 +74,9 @@ def test_set_attributes_with_content_type(self, m): self.canvas_object.set_attributes(attributes) self.assertTrue(hasattr(self.canvas_object, "content-type")) - self.assertEqual(getattr(self.canvas_object, 'content-type'), "application/json") + self.assertEqual( + getattr(self.canvas_object, "content-type"), "application/json" + ) self.assertTrue(hasattr(self.canvas_object, "content_type")) self.assertEqual(self.canvas_object.content_type, "another_application/json") self.assertTrue(hasattr(self.canvas_object, "filename")) From 5c02d7ef1880e95dba0ba73ceba444dc6e3d1f43 Mon Sep 17 00:00:00 2001 From: Matthew Emond Date: Sun, 28 Apr 2024 23:33:11 -0400 Subject: [PATCH 4/7] Fix isort --- canvasapi/canvas_object.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/canvasapi/canvas_object.py b/canvasapi/canvas_object.py index 78ff891b..9fae89c8 100644 --- a/canvasapi/canvas_object.py +++ b/canvasapi/canvas_object.py @@ -1,6 +1,7 @@ +import warnings + import arrow import pytz -import warnings class CanvasObject(object): From 51e59d1de5b4bc14e871805bb7c794f9cfad5068 Mon Sep 17 00:00:00 2001 From: Matthew Emond Date: Mon, 29 Apr 2024 00:11:19 -0400 Subject: [PATCH 5/7] Add failing test to demonstrate issue with content_type conversion --- tests/test_canvas_object.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/test_canvas_object.py b/tests/test_canvas_object.py index 859fb8aa..e083cd3a 100644 --- a/tests/test_canvas_object.py +++ b/tests/test_canvas_object.py @@ -81,3 +81,22 @@ def test_set_attributes_with_content_type(self, m): self.assertEqual(self.canvas_object.content_type, "another_application/json") self.assertTrue(hasattr(self.canvas_object, "filename")) self.assertEqual(self.canvas_object.filename, "example.json") + + def test_set_attributes_with_content_type_reversed(self, m): + # Reversed the order of the attributes to test overwrite behavior + attributes = { + "content_type": "another_application/json", + "content-type": "application/json", + "filename": "example.json", + } + + self.canvas_object.set_attributes(attributes) + + self.assertTrue(hasattr(self.canvas_object, "content-type")) + self.assertEqual( + getattr(self.canvas_object, "content-type"), "application/json" + ) + self.assertTrue(hasattr(self.canvas_object, "content_type")) + self.assertEqual(self.canvas_object.content_type, "another_application/json") + self.assertTrue(hasattr(self.canvas_object, "filename")) + self.assertEqual(self.canvas_object.filename, "example.json") From 66680c6f5b1089d9bb73200f443d81a1638cad75 Mon Sep 17 00:00:00 2001 From: Matthew Emond Date: Mon, 29 Apr 2024 00:35:13 -0400 Subject: [PATCH 6/7] Add failing test to check for DeprecationWarning when accessing content-type instead of content_type --- tests/test_canvas_object.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_canvas_object.py b/tests/test_canvas_object.py index e083cd3a..61aee77a 100644 --- a/tests/test_canvas_object.py +++ b/tests/test_canvas_object.py @@ -1,4 +1,5 @@ import unittest +import warnings from datetime import datetime import pytz @@ -100,3 +101,15 @@ def test_set_attributes_with_content_type_reversed(self, m): self.assertEqual(self.canvas_object.content_type, "another_application/json") self.assertTrue(hasattr(self.canvas_object, "filename")) self.assertEqual(self.canvas_object.filename, "example.json") + + def test__getattribute__content_type(self, m): + attributes = {"content-type": "application/json"} + self.canvas_object.set_attributes(attributes) + + warnings.simplefilter("always", DeprecationWarning) + + with warnings.catch_warnings(record=True) as warning_list: + self.canvas_object.__getattribute__("content-type") + + self.assertEqual(len(warning_list), 1) + self.assertEqual(warning_list[0].category, DeprecationWarning) From 583e9c33cd3541679de3e1d76b3082c47f56dca4 Mon Sep 17 00:00:00 2001 From: Matthew Emond Date: Mon, 29 Apr 2024 01:06:22 -0400 Subject: [PATCH 7/7] Moved content-type attribute deprecation warning to getter --- canvasapi/canvas_object.py | 17 +++++++++-------- tests/test_canvas_object.py | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/canvasapi/canvas_object.py b/canvasapi/canvas_object.py index 9fae89c8..54b6ed4e 100644 --- a/canvasapi/canvas_object.py +++ b/canvasapi/canvas_object.py @@ -13,6 +13,15 @@ class CanvasObject(object): """ def __getattribute__(self, name): + if name == "content-type": + warnings.warn( + ( + "The 'content-type' attribute will be removed " + "in a future version. Please use " + "'content_type' instead." + ), + DeprecationWarning, + ) return super(CanvasObject, self).__getattribute__(name) def __init__(self, requester, attributes): @@ -64,14 +73,6 @@ def set_attributes(self, attributes): self.__setattr__(attribute, value) if attribute == "content-type": self.__setattr__("content_type", value) - warnings.warn( - ( - "The 'content-type' attribute will be removed " - "in a future version. Please use " - "'content_type' instead." - ), - UserWarning, - ) try: naive = arrow.get(str(value)).datetime diff --git a/tests/test_canvas_object.py b/tests/test_canvas_object.py index 61aee77a..bad1d599 100644 --- a/tests/test_canvas_object.py +++ b/tests/test_canvas_object.py @@ -102,7 +102,7 @@ def test_set_attributes_with_content_type_reversed(self, m): self.assertTrue(hasattr(self.canvas_object, "filename")) self.assertEqual(self.canvas_object.filename, "example.json") - def test__getattribute__content_type(self, m): + def test__getattribute__content_type_warns(self, m): attributes = {"content-type": "application/json"} self.canvas_object.set_attributes(attributes)