-
Notifications
You must be signed in to change notification settings - Fork 22
Testing the utils #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| [run] | ||
| omit = *tests* |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,3 +44,5 @@ docs/_build | |
|
|
||
| # IDEs | ||
| /.idea | ||
| *.ropeproject | ||
| *.swp | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,3 +11,4 @@ Contributors | |
| ~~~~~~~~~~~~ | ||
|
|
||
| * Khaled Porlin - https://github.com/porlin72 | ||
| * Agam Dua - https://github.com/agamdua | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| from __future__ import print_function, unicode_literals | ||
|
|
||
| import unittest | ||
|
|
||
| from drf_braces.utils import ( | ||
| get_class_name_with_new_suffix, | ||
| get_attr_from_base_classes, | ||
| ) | ||
| from rest_framework import fields | ||
|
|
||
|
|
||
| class TestUtils(unittest.TestCase): | ||
| def test_get_class_name_with_new_suffix(self): | ||
| new_name = get_class_name_with_new_suffix( | ||
| klass=fields.IntegerField, | ||
| existing_suffix='Field', | ||
| new_suffix='StrawberryFields' | ||
| ) | ||
| self.assertEqual(new_name, 'IntegerStrawberryFields') | ||
|
|
||
| new_name = get_class_name_with_new_suffix( | ||
| klass=fields.IntegerField, | ||
| existing_suffix='straws', | ||
| new_suffix='Blueberries' | ||
| ) | ||
| self.assertEqual(new_name, 'IntegerFieldBlueberries') | ||
|
|
||
| def test_get_attr_from_base_classes(self): | ||
| Parent = type(str('Parent'), (), {'fields': 'pancakes'}) | ||
|
|
||
| self.assertEqual( | ||
| get_attr_from_base_classes((Parent,), [], 'fields'), 'pancakes' | ||
| ) | ||
|
|
||
| self.assertEqual( | ||
| get_attr_from_base_classes( | ||
| (Parent,), {'fields': 'mushrooms'}, 'fields' | ||
| ), | ||
| 'mushrooms' | ||
| ) | ||
|
|
||
| self.assertEqual( | ||
| get_attr_from_base_classes((Parent,), [], '', default='maple_syrup'), | ||
| 'maple_syrup' | ||
| ) | ||
|
|
||
| with self.assertRaises(AttributeError): | ||
| get_attr_from_base_classes( | ||
| (Parent,), {'fields': 'mushrooms'}, 'catchmeifyoucan' | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. lol
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💃 |
||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -117,6 +117,21 @@ def initialize_class_using_reference_object(reference_object, klass, **kwargs): | |
|
|
||
|
|
||
| def get_class_name_with_new_suffix(klass, existing_suffix, new_suffix): | ||
| """ | ||
| Generates new name by replacing the existing suffix with a new one. | ||
|
|
||
| Args: | ||
| klass (type): original class from which new name is generated | ||
| existing_suffix (str): the suffix which needs to remain where it is | ||
| new_suffix (str): the new suffix desired | ||
|
|
||
| Example: | ||
| >>> get_class_name_with_new_suffix(FooForm, 'Form', 'NewForm') | ||
| 'FooNewForm' | ||
|
|
||
| Returns: | ||
| new_name (str): the name with the new suffix | ||
| """ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. example might be nice: |
||
| class_name = klass.__name__ | ||
|
|
||
| if existing_suffix in class_name: | ||
|
|
@@ -129,7 +144,27 @@ def get_class_name_with_new_suffix(klass, existing_suffix, new_suffix): | |
| return new_name | ||
|
|
||
|
|
||
| def get_attr_from_base_classes(bases, attrs, attr, **kwargs): | ||
| def get_attr_from_base_classes(bases, attrs, attr, default=None): | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this is acceptable, I think we can merge. The rest of the comments were about docstrings
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fine. still not a fan but ok. |
||
| """ | ||
| The attribute is retrieved from the base classes if they are not already | ||
| present on the object. | ||
|
|
||
| Args: | ||
| bases (tuple, list): The base classes for a class. | ||
| attrs (dict): The attributes of the class. | ||
| attr (str): Specific attribute being looked for. | ||
| default (any): Whatever default value is expected if the | ||
| attr is not found. | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can add explicit
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
How will the behavior differ? I would prefer to add it as a kwarg.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. >>> def default(default=None):
... if default is not None:
... return default
... raise ValueError
...
>>> default(default=5)
5
>>> default(default='')
''
>>> default()
Traceback (most recent call last):
File "<ipython-input-4-7b40379d4ea0>", line 1, in <module>
default()
File "<ipython-input-1-234c4a43a49c>", line 4, in default
raise ValueError
ValueError
>>> default(default=None)
Traceback (most recent call last):
File "<ipython-input-5-d1b4f539633c>", line 1, in <module>
default(None)
File "<ipython-input-1-234c4a43a49c>", line 4, in default
raise ValueError
ValueError
>>> def default(**kwargs):
... if 'default' in kwargs:
... return kwargs['default']
... raise ValueError
...
>>> default(default=5)
5
>>> default(default='')
''
>>> default(default=None) # <===== notice this does not blow up now
>>> default()
Traceback (most recent call last):
File "<ipython-input-12-7b40379d4ea0>", line 1, in <module>
default()
File "<ipython-input-8-30e55c8618b5>", line 4, in default
raise ValueError
ValueError
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems like its a bit crazy 😮 On a more practical note though, is this something that can ever affect this repository?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. probably not but it makes me happy 😄
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if you can achieve the same with explicit kwarg as illustrated above, sure... |
||
| Returns: | ||
| attribute value as found in base classes or a default when attribute | ||
| is not found and default is provided. | ||
|
|
||
| Raises: | ||
| AttributeError: When the attribute is not present anywhere in the | ||
| call chain hierarchy specified through bases and the attributes | ||
| of the class itself | ||
| """ | ||
| if attr in attrs: | ||
| return attrs[attr] | ||
|
|
||
|
|
@@ -139,8 +174,8 @@ def get_attr_from_base_classes(bases, attrs, attr, **kwargs): | |
| except AttributeError: | ||
| continue | ||
|
|
||
| if 'default' in kwargs: | ||
| return kwargs['default'] | ||
| if default: | ||
| return default | ||
|
|
||
| raise AttributeError( | ||
| 'None of the bases have {} attribute' | ||
|
|
||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is
defaultused somewhere? I saw thatdefaultis provided in the code asFormSerializerOptions. This seems odd to me since we are returning a string or a class.Refer especially to the docstring
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this does not return str or default. this returns value found in either using these priorities:
__new__)this is really meant to mimick:
so in https://github.com/agamdua/django-rest-framework-braces/blob/test/utils/drf_braces/serializers/form_serializer.py#L120-L122 I lookup if
_options_classis defined as explicit attribute in the to-be created class. if yes, I use that. if not, I try to find it in any of the bases. and if not found there, I return default which usesFormSerializerOptionsThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So its always intended to be a class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not following.
get_attr_from_base_classespretty does what Python does internally when class is already created:when looking for attribute
fooexcept in my case I dont have access to mro since class has not been created yet....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it.