Coding 2023-03-22
Well, I'm not sick any more.
So, let's take a look at MOTR's code and imagine updating it.
Going through in order, we have the helper method not_accumulable_because, which is... Only called from not_flex_out_because? Which is only called from artifact._parametric_not_flex_out. Which is used as a validator for artifact.Condenser and artifact.BasicOutputConverter. For now, let's ignore what's going on in artifact, except insofar as this code is actually being used...
Putting all of this together, and keeping in mind that I want to relax the restrictions on multivalue labels, the final result is: one function like so:
def not_flex_out_because(self) -> typing.Iterator[str]:
if self.input:
yield "Unexpected use of parametric with associated inputs."
if self.iterated_labels:
yield (
"The base parametric for an Output should not force iteration."
)
I dropped the restriction on required/exclusive labels, because I think the singleton reforms handle that, as well.
The definition of expected_labels changes to return self.iterated_labels | self.exclusive_labels, and it probably needs a name change.
Next, we have providing and also_providing, which change like so:
@classmethod
def iterating_over(cls, labels: ...) -> Metadata:
label_set = frozenset(labels)
return cls(iterated_labels=label_set, selection_labels=label_set)
def also_iterating_over(self, label: ...) -> Metadata:
return attr.evolve(
self,
iterated_labels=self.iterated_labels.union([label]),
selection_labels=self.selection_labels.union([label]),
)
Next, we have as_maximal, which maybe needs a name change, but I also have some simplifications planned. Something like...
class Universe(enum.Enum):
UNIVERSE = enum.auto()
def __and__(self, other):
return other
__rand__ = __and__
def __rsub__(self, other):
return frozenset()
# Don't know if this one is needed.
def __contains__(self, item):
return True
Which would be used as the default value of multivalue_labels. So as_maximal becomes:
def as_maximal(self) -> Metadata:
return attr.evolve(
self,
multivalue_labels=self.multivalue_labels & self.selection_labels,
)
Similar changes to as_requiring:
def as_exclusive(self) -> Metadata:
return attr.evolve(
self,
iterated_labels=frozenset(),
exclusive_labels=self.expected_labels,
)
Then we get into narrow_labels, which becomes...
def reduce_iteration_to(self, labels: _selection.Labels) -> Metadata:
if not labels <= self.iterated_labels:
raise ValueError
no_longer_iterated_labels = self.iterated_labels - labels
return attr.evolve(
self,
iterated_labels=labels,
exclusive_labels=self.exclusive_labels - no_longer_iterated_labels,
)
And I think I'll leave it there, because something is pretty suspicious about this, in a way that's making me suspect that my model is incomplete or incorrect. There's a few things going on that look suspicious:
- Given this logic, which is identical to the previous logic except for the names, I can't tell how the forbid_narrowing concept from elsewhere in the code is supposed to work. Like, this code is, um, pretty insistent...
- Oh, wait, I sort of get it. forbid_narrowing can't directly affect what happens to exclusive_labels, but it does reduce the iterated_labels... In other words, "You can't squeeze this if I stomp it flat first." I'm now provisionally okay with all of this except for the names.
In any case, I need to think about this a bit more, then change things if I feel the need, or just move on down through the rest of the methods and functions.
Good night.