objetto
Advanced tools
| # -*- coding: utf-8 -*- | ||
| import pytest | ||
| from objetto import Object, attribute | ||
| class Person(Object): | ||
| friend = attribute("Person") | ||
| def test_lazy_check(): | ||
| class Worker(Person): | ||
| friend = attribute(Person) | ||
| with pytest.raises(TypeError): | ||
| class Boss(Worker): | ||
| friend = attribute(None) | ||
| if __name__ == "__main__": | ||
| pytest.main() |
| Metadata-Version: 2.1 | ||
| Name: objetto | ||
| Version: 1.26.0 | ||
| Version: 1.27.0 | ||
| Summary: Object-oriented framework for building smart applications and APIs | ||
@@ -5,0 +5,0 @@ Home-page: https://github.com/brunonicko/objetto |
@@ -81,2 +81,3 @@ LICENSE | ||
| tests/test_data_serialization.py | ||
| tests/test_lazy_check.py | ||
| tests/test_list_object.py | ||
@@ -83,0 +84,0 @@ tests/test_object_serialization.py |
@@ -565,3 +565,3 @@ # -*- coding: utf-8 -*- | ||
| # Store attributes, check implementation of abstract attributes along the way. | ||
| attributes = {} # type: Dict[str, BaseAttribute] | ||
| attributes = {} # type: Dict[str, Tuple[Type, BaseAttribute]] | ||
| abstract_attributes = {} # type: Dict[str, Tuple[Type, BaseAttribute]] | ||
@@ -580,11 +580,24 @@ if attribute_type is not None: | ||
| # Implementing checked abstract attribute. | ||
| # Implementing checked attribute. | ||
| is_abstract = member_name in abstract_attributes | ||
| if ( | ||
| member_name in abstract_attributes | ||
| is_abstract | ||
| and abstract_attributes[member_name][1].relationship.checked | ||
| ) or ( | ||
| member_name in attributes | ||
| and attributes[member_name][1].relationship.checked | ||
| ): | ||
| abstract_base, abstract_attribute = abstract_attributes[ | ||
| member_name | ||
| ] | ||
| # Labels for messages. | ||
| abstract_label = "abstract" if is_abstract else "super" | ||
| member_label = "implementation" if is_abstract else "override" | ||
| # Get abstract/super attribute. | ||
| if is_abstract: | ||
| abstract_base, abstract_attribute = abstract_attributes[ | ||
| member_name | ||
| ] | ||
| else: | ||
| abstract_base, abstract_attribute = attributes[member_name] | ||
| # Not an attribute. | ||
@@ -607,9 +620,11 @@ if not isinstance(member, attribute_type): | ||
| error = ( | ||
| "attribute '{}.{}' value type '{}' is not " | ||
| "compatible with abstract '{}.{}' constant " | ||
| "attribute type '{}'" | ||
| "attribute {} '{}.{}' value type '{}' is not " | ||
| "compatible with {} '{}.{}' constant attribute " | ||
| "type '{}'" | ||
| ).format( | ||
| member_label, | ||
| name, | ||
| member_name, | ||
| type(member).__name__, | ||
| abstract_label, | ||
| abstract_base.__name__, | ||
@@ -633,6 +648,6 @@ member_name, | ||
| error = ( | ||
| "can't implement abstract attribute '{}.{}' in " | ||
| "'{}.{}' with unsupported member type '{}', " | ||
| "expected '{}'" | ||
| "can't override {} attribute '{}.{}' in '{}.{}' " | ||
| "with unsupported member type '{}', expected '{}'" | ||
| ).format( | ||
| abstract_label, | ||
| abstract_base.__name__, | ||
@@ -693,7 +708,9 @@ member_name, | ||
| error = ( | ||
| "abstract attribute '{}.{}' declares types, but " | ||
| "implementation in '{}.{}' does not" | ||
| "{} attribute '{}.{}' declares types, but {} in " | ||
| "'{}.{}' does not" | ||
| ).format( | ||
| abstract_label, | ||
| abstract_base.__name__, | ||
| member_name, | ||
| member_label, | ||
| name, | ||
@@ -760,8 +777,10 @@ member_name, | ||
| error = ( | ||
| "types in attribute '{}.{}' {} are not compatible " | ||
| "with abstract '{}.{}' attribute types {}" | ||
| "types in {} attribute '{}.{}' {} are not " | ||
| "compatible with {} '{}.{}' attribute types {}" | ||
| ).format( | ||
| member_label, | ||
| name, | ||
| member_name, | ||
| get_type_names(member_types), | ||
| abstract_label, | ||
| abstract_base.__name__, | ||
@@ -773,21 +792,12 @@ member_name, | ||
| # Check other parameters. | ||
| if abstract_attribute.changeable and not member.changeable: | ||
| error = ( | ||
| "abstract attribute '{}.{}' is changeable, but " | ||
| "implementation in '{}.{}' is not" | ||
| ).format( | ||
| abstract_base.__name__, | ||
| member_name, | ||
| name, | ||
| member_name, | ||
| ) | ||
| raise TypeError(error) | ||
| # Can't go from non-changeable to changeable. | ||
| if not abstract_attribute.changeable and member.changeable: | ||
| error = ( | ||
| "abstract attribute '{}.{}' is not changeable, but " | ||
| "implementation in '{}.{}' is" | ||
| "{} attribute '{}.{}' is not changeable, but {} in " | ||
| "'{}.{}' is" | ||
| ).format( | ||
| abstract_label, | ||
| abstract_base.__name__, | ||
| member_name, | ||
| member_label, | ||
| name, | ||
@@ -798,9 +808,12 @@ member_name, | ||
| # Can't go from deletable to non-deletable. | ||
| if abstract_attribute.deletable and not member.deletable: | ||
| error = ( | ||
| "abstract attribute '{}.{}' is deletable, but " | ||
| "implementation in '{}.{}' is not" | ||
| "{} attribute '{}.{}' is deletable, but {} in " | ||
| "'{}.{}' is not" | ||
| ).format( | ||
| abstract_label, | ||
| abstract_base.__name__, | ||
| member_name, | ||
| member_label, | ||
| name, | ||
@@ -810,17 +823,6 @@ member_name, | ||
| raise TypeError(error) | ||
| if not abstract_attribute.deletable and member.deletable: | ||
| error = ( | ||
| "abstract attribute '{}.{}' is not deletable, but " | ||
| "implementation in '{}.{}' is" | ||
| ).format( | ||
| abstract_base.__name__, | ||
| member_name, | ||
| name, | ||
| member_name, | ||
| ) | ||
| raise TypeError(error) | ||
| # Store attribute. | ||
| if isinstance(member, attribute_type): | ||
| attributes[member_name] = member | ||
| attributes[member_name] = base, member | ||
@@ -835,9 +837,11 @@ # Abstract attribute, remember it. | ||
| # Store attribute names. | ||
| # Get attribute dict and store attribute names. | ||
| attribute_dict = {} | ||
| attribute_names = {} | ||
| if attribute_type is not None: | ||
| for attribute_name, attribute in iteritems(attributes): | ||
| for attribute_name, (_, attribute) in iteritems(attributes): | ||
| attribute_dict[attribute_name] = attribute | ||
| attribute_names[attribute] = attribute_name | ||
| type(cls).__attributes[cls] = DictState(attributes) | ||
| type(cls).__attributes[cls] = DictState(attribute_dict) | ||
| type(cls).__attribute_names[cls] = DictState(attribute_names) | ||
@@ -847,3 +851,3 @@ | ||
| abstract_members = set(cls.__dict__.get("__abstractmethods__", ())) | ||
| for attribute_name, attribute in iteritems(attributes): | ||
| for attribute_name, attribute in iteritems(attribute_dict): | ||
| if attribute.abstracted: | ||
@@ -850,0 +854,0 @@ abstract_members.add(attribute_name) |
+4
-4
@@ -207,3 +207,3 @@ # -*- coding: utf-8 -*- | ||
| value, # type: T | ||
| checked=None, # type: Optional[bool] | ||
| checked=True, # type: bool | ||
| serialized=False, # type: bool | ||
@@ -224,4 +224,4 @@ serializer=None, # type: LazyFactory | ||
| :param checked: Whether to type check when implementing abstract constant attribute. | ||
| :type checked: bool or None | ||
| :param checked: Whether to type check when overriding this constant attribute. | ||
| :type checked: bool | ||
@@ -263,3 +263,3 @@ :param serialized: Whether should be serialized. | ||
| subtypes=False, | ||
| checked=abstracted if checked is None else checked, | ||
| checked=checked, | ||
| serialized=serialized, | ||
@@ -266,0 +266,0 @@ serializer=serializer, |
+1
-1
| Metadata-Version: 2.1 | ||
| Name: objetto | ||
| Version: 1.26.0 | ||
| Version: 1.27.0 | ||
| Summary: Object-oriented framework for building smart applications and APIs | ||
@@ -5,0 +5,0 @@ Home-page: https://github.com/brunonicko/objetto |
+1
-1
@@ -8,3 +8,3 @@ import setuptools | ||
| name="objetto", | ||
| version="1.26.0", | ||
| version="1.27.0", | ||
| author="Bruno Nicko", | ||
@@ -11,0 +11,0 @@ author_email="brunonicko@gmail.com", |
Sorry, the diff of this file is too big to display
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
1029446
0.04%96
1.05%25508
0.06%