Skip to content

Commit 2af2edf

Browse files
author
Simon Beyzerov
committed
fix minor bugs in validation logic
1 parent 4acbb08 commit 2af2edf

File tree

3 files changed

+35
-47
lines changed

3 files changed

+35
-47
lines changed

cpp/csp/engine/Struct.cpp

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,18 @@ StructMeta::StructMeta( const std::string & name, const Fields & fields, bool is
131131
if( !rv.second )
132132
CSP_THROW( ValueError, "csp Struct " << name << " attempted to add existing field " << m_fields[ idx ] -> fieldname() );
133133
}
134+
135+
// A non-strict struct may not inherit (directly or indirectly) from a strict base
136+
bool encountered_non_strict = false;
137+
for ( const StructMeta * cur = this; cur; cur = cur -> m_base.get() )
138+
{
139+
encountered_non_strict |= !cur -> isStrict();
140+
if ( encountered_non_strict && cur -> isStrict() )
141+
CSP_THROW( ValueError,
142+
"Strict '" << m_name
143+
<< "' has non-strict inheritance of strict base '"
144+
<< cur -> name() << "'" );
145+
}
134146
}
135147

136148
StructMeta::~StructMeta()
@@ -498,40 +510,29 @@ void StructMeta::destroy( Struct * s ) const
498510
}
499511

500512
void StructMeta::validate( const Struct * s ) const
501-
{
502-
bool encountered_non_strict = false;
503-
513+
{
504514
for ( const StructMeta * cur = this; cur; cur = cur -> m_base.get() )
505515
{
506-
encountered_non_strict |= !cur -> isStrict();
507516
if ( !cur -> isStrict() )
508517
continue;
509-
510-
// Rule 1: A non-strict struct may not inherit (directly or indirectly) from a strict base
511-
if ( encountered_non_strict )
512-
CSP_THROW( ValueError,
513-
"Struct '" << s -> meta() -> name()
514-
<< "' has non-strict inheritance of strict base '"
515-
<< cur -> name() << "'" );
516518

517-
// Rule 2: All local fields are set
518-
std::string missing_fields;
519-
for ( const auto & field : cur -> m_fields )
519+
if ( !cur -> allFieldsSet( s ) )
520520
{
521-
if ( !field -> isSet( s ) )
521+
std::string missing_fields;
522+
for ( const auto & field : cur -> m_fields )
522523
{
523-
if ( missing_fields.empty() )
524-
missing_fields = field -> fieldname();
525-
else
526-
missing_fields += ", " + field -> fieldname();
524+
if ( !field -> isSet( s ) )
525+
{
526+
if ( missing_fields.empty() )
527+
missing_fields = field -> fieldname();
528+
else
529+
missing_fields += ", " + field -> fieldname();
530+
}
527531
}
528-
}
529-
530-
// Raise error if any fields are missing
531-
if ( !missing_fields.empty() )
532532
CSP_THROW( ValueError,
533-
"Strict struct '" << cur -> name()
533+
"Strict struct '" << s -> meta() -> name()
534534
<< "' missing required fields: " << missing_fields );
535+
}
535536
}
536537
}
537538

csp/impl/wiring/edge.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,9 +202,10 @@ def __getattr__(self, key):
202202
elemtype = typ.metadata(typed=True).get(key)
203203
if elemtype is None:
204204
raise AttributeError("'%s' object has no attribute '%s'" % (self.tstype.typ.__name__, key))
205-
if key in typ.optional_fields():
205+
if (key in typ.optional_fields()) and (typ.is_strict()):
206206
raise AttributeError(
207-
"Cannot access optional field '%s' on object '%s' at graph time" % (key, self.tstype.typ.__name__)
207+
"Cannot access optional field '%s' on strict struct object '%s' at graph time"
208+
% (key, self.tstype.typ.__name__)
208209
)
209210
return csp.struct_field(self, key, elemtype)
210211

csp/tests/test_strict_structs.py

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ def g_fail():
142142

143143
with self.assertRaisesRegex(
144144
AttributeError,
145-
"Cannot access optional field 'opt_str' on object 'MyStrictStruct' at graph time",
145+
"Cannot access optional field 'opt_str' on strict struct object 'MyStrictStruct' at graph time",
146146
):
147147
csp.run(g_fail, starttime=datetime(2023, 1, 1))
148148

@@ -264,23 +264,10 @@ def test_nonstrict_cannot_inherit_strict(self):
264264
class StrictBase(csp.Struct, allow_unset=False):
265265
base_val: int
266266

267-
class NonStrictChild1(StrictBase, allow_unset=True):
268-
child_val1: Optional[int] = None
269-
270-
class NonStrictChild2(NonStrictChild1, allow_unset=True):
271-
child_val2: Optional[int] = None
272-
273-
class NonStrictChild3(NonStrictChild2, allow_unset=True):
274-
child_val3: Optional[int] = None
275-
276-
with self.assertRaisesRegex(ValueError, "non-strict inheritance of strict base"):
277-
NonStrictChild1(base_val=1, child_val1=2)
278-
279267
with self.assertRaisesRegex(ValueError, "non-strict inheritance of strict base"):
280-
NonStrictChild2(base_val=3, child_val1=4, child_val2=5)
281268

282-
with self.assertRaisesRegex(ValueError, "non-strict inheritance of strict base"):
283-
NonStrictChild3(base_val=6, child_val1=7, child_val2=8, child_val3=9)
269+
class NonStrictChild1(StrictBase, allow_unset=True):
270+
child_val1: Optional[int] = None
284271

285272
def test_nonstrict_strict_nonstrict_inheritance_order(self):
286273
"""inheritance order NonStrict -> Strict -> NonStrict raises an error"""
@@ -291,11 +278,10 @@ class NonStrictBase(csp.Struct, allow_unset=True):
291278
class StrictMiddle(NonStrictBase, allow_unset=False):
292279
middle_val: int
293280

294-
class NonStrictChild(StrictMiddle, allow_unset=True):
295-
child_val: Optional[int] = None
296-
297281
with self.assertRaisesRegex(ValueError, "non-strict inheritance of strict base"):
298-
NonStrictChild(base_val=1, middle_val=2, child_val=3)
282+
283+
class NonStrictChild(StrictMiddle, allow_unset=True):
284+
child_val: Optional[int] = None
299285

300286
def test_nested_struct_serialization(self):
301287
"""to_dict / from_dict work with nested strict & non-strict structs"""
@@ -344,7 +330,7 @@ def main_graph():
344330
csp.print("", res)
345331

346332
with self.assertRaisesRegex(
347-
AttributeError, "Cannot access optional field 'is_active' on object 'Test' at graph time"
333+
AttributeError, "Cannot access optional field 'is_active' on strict struct object 'Test' at graph time"
348334
):
349335
csp.build_graph(main_graph)
350336

0 commit comments

Comments
 (0)