I've got some major changes that I want to make in my punq fork, and I decided I want to write them out here as a dry run before doing them. That way there's a chance I'll notice if I get in over my head.
- For aesthetic reasons, I want to try replacing the instance keyword argument with an Instance or Singleton class that acts as an argument to the factory keyword, but with special-casing. This represents a breaking change, but there are plenty more where that came from, so it's fine-ish.
- The builder type annotation is too restrictive.
- I don't know what's going on with args. I'll have to come back to that, though a cursory look makes it look like it should be a Dict[str, Any].
- _registrations should be a DefaultDict[str, List[Registration]], and _localns should be gone. (Maybe it should be with Tuple[Registration, ...])
- As should the specific implementation of _get_needs_for_ctor. Instead, it should crawl the mro for a class that defines __init__ in its __dict__, then look up that class's __module__ in sys.modules, and from there get the global module scope. Then, it should call get_type_hints(init, module_globals), and probably pop "return" from the result. No error wrapping.
- Various parts of the library will have to perform type-to-string conversion, and that should be pushed to as high a level as possible.
- I don't know if I want to change it, but I'm not sure I understand why concrete impls can't be registered with keyword arguments. My inclination is to get as much code as possible shared between the various paths.
- build_context looks fine, though the usage of explicit __getitem__ confuses me.
- _update_localns is gone.
- The signature of Registry.register should end up something like service: Union[str, type], factory: Optional[Callable], scope: Scope, /, **kwargs: Any. This allows passing any kwargs, and requires an explicit factory to be provided when setting the scope. This is a (minor, I think) expressiveness hit in terms of what's required to register a concrete impl as a singleton, but I think the tradeoff is worth it. If it turns out problematic, my first attempt will be to change things more, by replacing the scope argument with more wrapper classes.
- ResolutionTarget looks okay with str and List[Registration], but the generic_parameter property freaks me out a little. It does, however, show that one thing that should be done when interpreting annotations and resolve arguments is, if the top node is an index operation, and the lhs is typing.List, in some way or other, then the argument should be all attribute access, and that's what gets resolved.
- I think ResolutionContext is about fine, I'll figure out the annotations later.
- Container is probably the most relevant part, but most of it follows from the previous notes.
I'll write up the supporting functions on paper later. I think I basically have everything I need, between today and yesterday.
I want to wind down now.