def test_evaluate_attrs_2(): actual = evaluate_attrs( Struct(attrs=Namespace( class__table=True, class__foo=lambda foo: True, data=1, data2=lambda foo: foo, style__foo=1, style__bar=lambda foo: f'foo{3}', ), ), foo=3, ) expected = { 'class': { 'table': True, 'foo': True, }, 'style': { 'foo': 1, 'bar': 'foo3' }, 'data': 1, 'data2': 3, } assert actual == expected
def test_empty_class_and_struct_then_something(): assert (str( evaluate_attrs(Struct(attrs={ 'class': {}, 'style': {}, 'z': 'bar', }))) == ' z="bar"')
def test_evaluate_attrs(): class Foo: def __init__(self): self.attrs = Namespace( a=3, b=lambda foo: foo + 7, class__a=True, class__b=lambda foo: True, style__a=3, style__b=lambda foo: foo + 7, ) expected = { 'a': 3, 'b': 8, 'class': { 'a': True, 'b': True, }, 'style': { 'a': 3, 'b': 8, }, } assert evaluate_attrs(Foo(), foo=1) == expected
def bind(self, *, parent=None, request=None): assert parent is None or parent._is_bound assert not self._is_bound result = copy.copy(self) if parent: is_root = False iommi_style = get_iommi_style_name(parent) else: is_root = True iommi_style = get_iommi_style_name(self) result = apply_style(iommi_style, result, is_root) result._declared = self del self # to prevent mistakes when changing the code below if parent is None: result._request = request if result._name is None: result._name = 'root' result._iommi_collected_assets = {} result._parent = parent result._bound_members = Struct() result._is_bound = True evaluate_parameters = { **(parent.iommi_evaluate_parameters() if parent is not None else {}), **result.own_evaluate_parameters(), 'traversable': result, } if parent is None: evaluate_parameters['request'] = request result._evaluate_parameters = evaluate_parameters if hasattr(result, 'include'): include = evaluate_strict(result.include, **evaluate_parameters) if not bool(include): return None result.include = True result.on_bind() # on_bind has a chance to hide itself if result.include is False: return None if hasattr(result, 'attrs'): result.attrs = evaluate_attrs(result, **result.iommi_evaluate_parameters()) evaluated_attributes = [k for k, v in items(result.get_declared('refinable_members')) if is_evaluated_refinable(v)] evaluate_members(result, evaluated_attributes, **evaluate_parameters) if hasattr(result, 'extra_evaluated'): result.extra_evaluated = evaluate_strict_container(result.extra_evaluated or {}, **evaluate_parameters) return result
def test_evaluate_attrs_hide_debug_paths(): actual = evaluate_attrs( Struct( attrs=Namespace(class__table=True, ), _name='foo', iommi_dunder_path='<path here>', ), ) expected = { 'class': { 'table': True, }, 'style': {}, } assert actual == expected
def test_class_style_callable(): actual = evaluate_attrs( Namespace( attrs__class=lambda foo: {'foo' + foo: True}, attrs__style=lambda foo: {'hey' + foo: 'yo'}, _name='foo', iommi_dunder_path='<path here>', ), foo='bar', ) expected = { 'class': { 'foobar': True, }, 'style': { 'heybar': 'yo', }, } assert actual == expected
def bind(self, *, parent=None, request=None): assert parent is None or parent._is_bound assert not self._is_bound if parent is None: self._request = request if self._name is None: self._name = 'root' result = copy.copy(self) result._declared = self del self # to prevent mistakes when changing the code below result._parent = parent result._is_bound = True evaluate_parameters = { 'traversable': result, **(parent.iommi_evaluate_parameters() if parent is not None else {}), **result.own_evaluate_parameters(), } if parent is None: evaluate_parameters['request'] = request result._evaluate_parameters = evaluate_parameters if hasattr(result, 'include'): include = evaluate_strict(result.include, **evaluate_parameters) if not bool(include): return None else: include = MISSING if include is not MISSING: result.include = True rest_of_style = apply_style(result) # Styling has another chance of setting include to False if include is not MISSING and result.include is False: return None result.include = True result.on_bind() if rest_of_style: rest = apply_style_recursively(style_data=rest_of_style, obj=result) assert not rest, f'There is still styling data left for {result}: {rest_of_style}' # on_bind has a chance to hide itself if result.include is False: return None if hasattr(result, 'attrs'): result.attrs = evaluate_attrs(result, **result.iommi_evaluate_parameters()) evaluated_attributes = [ k for k, v in items(result.get_declared('refinable_members')) if is_evaluated_refinable(v) ] evaluate_members(result, evaluated_attributes, **evaluate_parameters) if hasattr(result, 'extra_evaluated'): result.extra_evaluated = evaluate_strict_container( result.extra_evaluated or {}, **evaluate_parameters) return result
def test_error_message_for_str_in_class(): with pytest.raises(AssertionError) as e: evaluate_attrs(Namespace(attrs__class='foo bar')) assert str(e.value).startswith('CSS classes')
def test_error_message_for_str_in_style(): with pytest.raises(AssertionError) as e: evaluate_attrs(Namespace(attrs__style='display: none')) assert str(e.value).startswith('CSS styles')
def render_attrs_test(attrs, **kwargs): return str(evaluate_attrs(Struct(attrs=attrs), **kwargs))