Routing: Factories for extendible transformers, mappings, smart defaults etc. #68
Replies: 3 comments 3 replies
-
|
Testing 123. |
Beta Was this translation helpful? Give feedback.
-
|
Example of routing: Switch-case clauses. Switch-case code blockSay you had the following code block in a function. if axis_format is None:
# If the total range is large, we might want to reduce the detail
if total_range_in_days > 365: # More than a year
axis_format = '%Y'
elif total_range_in_days > 30: # More than a month
axis_format = '%Y-%m'
elif total_range_in_days > 7: # More than a week
axis_format = '%Y-%m-%d'
elif total_range_in_days > 1: # More than a day
axis_format = '%Y-%m-%d %H:%M'
elif total_range_in_days > 0.041666666666666664: # More than an hour
axis_format = '%Y-%m-%d %H:%M:%S'
elif total_range_in_days > 0.0006944444444444444: # More than a minute
axis_format = '%Y-%m-%d %H:%M:%S.%L'
elif total_range_in_days > 0.000011574074074074073: # More than a second
axis_format = '%Y-%m-%d %H:%M:%S.%L'
else: # Less than a second
axis_format = '%Y-%m-%d %H:%M:%S.%L'Well, first of all, since you are a clean-code monk, you'll be tempted to factor out that logic to be in a Good. Now if you want your user to be able to control this aspect, you can add an optional parameter to your function with that You're better off now, but what if the context warrants changing that function often, or even worse: Just make some slight modifications to the already existing logic. You are again in danger of copy/paste/modifying a bunch of code, littering your otherwise beautifully concise module. Further, it's not the most convenient thing for the user, and you'll notice that most of the actual logic of the code above is determined by the We can do better. IntervalSwitchCase classHere's an example of better: You have Here's some starter code: from collections.abc import Callable
class IntervalSwitchCase(Callable):
def __init__(self, mapping, default):
# Store mapping as a sorted tuple
self.mapping = tuple(sorted(mapping, reverse=True))
self.default = default
def __call__(self, value):
# Implement switch case logic
for threshold, result in self.mapping:
if value > threshold:
return result
return self.default
def update(self, updates):
# Immutably update mapping
updated_mapping = dict(self.mapping)
updated_mapping.update(updates)
return IntervalSwitchCase(list(updated_mapping.items()), self.default)
def __setitem__(self, key, value):
# Support item assignment syntax
updated_mapping = dict(self.mapping)
updated_mapping[key] = value
return IntervalSwitchCase(list(updated_mapping.items()), self.default)
def __delitem__(self, key):
# Support item deletion syntax
updated_mapping = dict(self.mapping)
del updated_mapping[key]
return IntervalSwitchCase(list(updated_mapping.items()), self.default)Applying this to our # Define default_mapping and default for axis_format case
axis_format_default_mapping = (
(365, '%Y'),
(30, '%Y-%m'),
(7, '%Y-%m-%d'),
(1, '%Y-%m-%d %H:%M'),
(0.041666666666666664, '%Y-%m-%d %H:%M:%S'),
(0.0006944444444444444, '%Y-%m-%d %H:%M:%S.%L'),
(1.1574074074074073e-05, '%Y-%m-%d %H:%M:%S.%L')
)
axis_format_default = '%Y-%m-%d %H:%M:%S.%L'
# Create a IntervalSwitchCase instance for the axis_format
axis_format_selector = IntervalSwitchCase(axis_format_default_mapping, axis_format_default)
# Example usage
print(axis_format_selector(50)) # Output: '%Y-%m'
# Get an updated IntervalSwitchCase object with custom mapping
custom_selector = axis_format_selector.update({1: '%Y-%m-%d %H'})
print(custom_selector(0.5)) # Output: '%Y-%m-%d %H'A general
|
Beta Was this translation helpful? Give feedback.
-
Some patterns of routing |
Beta Was this translation helpful? Give feedback.



Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
The idea (or solution to a common "problem pattern") of parametrized transformers comes back a lot.
I've denoted the idea by many names such as:
Highlighted here is one of the cornerstone problems. There are many names to this because there's many angles we can approach the problem under. Different contexts bring about different "natural" interfaces to a same underlying problem.
It definitely would be useful to gain a bit more clarity on the underlying ontology so a useful taxonomy can be developed and used to better design reusable tools around this problem. In theory, it's the same underlying idea at the base of "dispatchers" such as
py2httpandfront, and is quite present in other "i2i" tools such asdol.Below are a few examples of where we actually implemented a tool for some sub-class of the declarative wrapping/transformer solution.
Examples
You get things like the extremely useful (though badly designed, since carries ancient legacies)
StrTupleDict
that is useful to express multi directional transformers from strings, tuples and dictionaries: Used a lot in the context of key transformation when using
dol.The main entropy-reducing part of
py2apiwas it's transformation mini-languages expressed in near-json objects that were then interpreted by interpreters such as InputTransThe "Input/Output Trans the i2.wrapper way" mentions that these could probably be boiled down to use i2.wrapper as their backend.
Indeed, i2.wrapper is a pretty solid and general base for such matters, though (1) I wonder if it's a complexity overkill versus having a few specific tools written without so many abstract layers, and (2) I still wonder if we should switch to using wrapt as our base, since it was written by someone who understands the annoying wrap-unfriendly traps deep end python laid out for us all!
Some more mentionables:
ext_mapping, but the io object resolution is parametrized through aresolve_to_iofunction, with a default that is itself a function whose parameters haven't been factored out to be declarative. In this discussion, we propose that: A declarative form (routing) for the io reader concernReferences
Quick search links
The links below will take you directly to the github advanced search with a few key terms where you might find more information. These are useful because it will give you a more "current" view of the landscape.
┆Issue is synchronized with this Asana task by Unito
Beta Was this translation helpful? Give feedback.
All reactions