Open matts1 opened 8 months ago
FWIW, I've mostly solved this by just doing the following:
# I strongly dislike how struct is defined, IMO the attrs should be curried
def struct(**attrs):
return lambda value, *, meta: subjects.struct(value, meta=meta, attrs=attrs)
def optional(factory):
def new_factory(value, *, meta):
# Optimisations could be done here to just pull all the methods from the parent and add the method is_none()
def some():
if value == None:
meta.add_failure("Wanted a value, but got None", None)
return factory(value, meta = meta)
def is_none():
if value != None:
meta.add_failure("Wanted None, but got a value", value)
return struct(some = some, is_none = is_none)
generic_subjects = struct(struct = struct, optional = optional)
You can then just write:
FooInfo = provider(fields = {"a": "(Optional[str])")
FooInfoSubject = generic_subjects.struct(a = generic_subjects.optional(subjects.str))
foo_some = FooInfo(a = "abc")
foo_none = FooInfo(a = None)
env.expect.that_value(foo_some, factory = FooInfoSubject).a().some().contains("abc")
env.expect.that_value(foo_none, factory = FooInfoSubject).a().is_none()
It's currently very hard to work with custom providers. One example of somewhere seriously lacking is if I want to do assertions on the following type:
I would like to be able to write something like:
I propose that we allow generics by turning generic types into functions. For example:
This would make the above predicates far more easily implemented (although the caveat is that it would require a change in matchers so that you could simply use them as a boolean predicate - at the moment, not matching simply fails the test).
We could also use this to easily solve #63 via the generic type
subjects.optional
(eg.subjects.optional(subjects.string)
).