in_n_out #
pluggable dependency injection and result processing.
Generally speaking, providers and processors are defined as follows:
Provider: TypeAlias = Callable[[], Any]
: a callable that can accept no arguments and returns an instance of some type. When we refer to aProcessor: TypeAlias = Callable[[Any], Any]
: a callable that accepts a single positional argument (an instance of some type) and returns anything (the return value is ignored).
Store #
Store(name: str)
A Store is a collection of providers and processors.
Source code in in_n_out/_store.py
206 207 208 209 210 211 212 213 |
|
namespace
property
writable
#
namespace: dict[str, object]
Return namespace for type resolution, if this store has one.
If no namespace is set, this will return an empty dict
.
clear #
clear() -> None
Clear all providers and processors.
Source code in in_n_out/_store.py
220 221 222 223 224 225 226 227 |
|
create
classmethod
#
create(name: str) -> Store
Create a new Store instance with the given name
.
This name can be used to refer to the Store in other functions.
Parameters:
-
name
(str
) –A name for the Store.
Returns:
-
Store
–A Store instance with the given
name
.
Raises:
-
KeyError
–If the name is already in use, or the name is 'global'.
Source code in in_n_out/_store.py
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
|
destroy
classmethod
#
destroy(name: str) -> None
Destroy Store instance with the given name
.
Parameters:
-
name
(str
) –The name of the Store.
Raises:
-
ValueError
–If the name matches the global store name.
-
KeyError
–If the name is not in use.
Source code in in_n_out/_store.py
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
|
get_store
classmethod
#
get_store(name: str | None = None) -> Store
Get a Store instance with the given name
.
Parameters:
-
name
(str
, default:None
) –The name of the Store.
Returns:
-
Store
–A Store instance with the given
name
.
Raises:
-
KeyError
–If the name is not in use.
Source code in in_n_out/_store.py
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
|
inject #
inject(func: Callable[P, R] | None = None, *, providers: bool = True, processors: bool = False, localns: dict | None = None, on_unresolved_required_args: RaiseWarnReturnIgnore | None = None, on_unannotated_required_args: RaiseWarnReturnIgnore | None = None, guess_self: bool | None = None) -> Callable[..., R] | Callable[[Callable[P, R]], Callable[..., R]]
Decorate func
to inject dependencies at calltime.
Assuming providers
is True (the default), this will attempt retrieve
instances of the types required by func
and inject them into func
at
calltime. The primary consequence of this is that func
may be called
without parameters (assuming the required providers have been registered).
See usages examples below.
Note that an injected function may still be explicitly invoked with parameters.
See register
for more information on how to register providers and processors.
Parameters:
-
func
(Callable
, default:None
) –A function to decorate. Type hints are used to determine what to inject.
-
providers
(bool
, default:True
) –Whether to inject dependency providers. If
True
(default), then when this function is called, arguments will be injected into the function call according to providers that have been registered in the store. -
processors
(bool
, default:False
) –Whether to invoke all processors for this function's return type the when this function is called. Important: this causes side effects. By default,
False
. Output processing can also be enabled (with additionl fine tuning) by using the@store.process_result
decorator. -
localns
(dict | None
, default:None
) –Optional local namespace for name resolution, by default None
-
on_unresolved_required_args
(RaiseWarnReturnIgnore
, default:None
) –What to do when a required parameter (one without a default) is encountered with an unresolvable type annotation. Must be one of the following (by default 'warn'):
'raise'
: immediately raise an exception'warn'
: warn and return the original function'return'
: return the original function without warning'ignore'
: continue decorating without warning (at call time, this function will fail without additional arguments).
-
on_unannotated_required_args
(RaiseWarnReturnIgnore
, default:None
) –What to do when a required parameter (one without a default) is encountered with an no type annotation. These functions are likely to fail when called later if the required parameter is not provided. Must be one of the following (by default 'warn'):
'raise'
: immediately raise an exception'warn'
: warn, but continue decorating'return'
: immediately return the original function without warning'ignore'
: continue decorating without warning.
-
guess_self
(bool
, default:None
) –Whether to infer the type of the first argument if the function is an unbound class method (by default,
True
) This is done as follows:- if
'.'
(but not'<locals>'
) is in the function's__qualname__
- and if the first parameter is named 'self' or starts with
"_"
- and if the first parameter annotation is
inspect.empty
- then the name preceding
func.__name__
in the function's__qualname__
(which is usually the class name), is looked up in the function's__globals__
namespace. If found, it is used as the first parameter's type annotation.
This allows class methods to be injected with instances of the class.
- if
Returns:
-
Callable
–A function with dependencies injected
Examples:
>>> import in_n_out as ino
>>> class Thing:
... def __init__(self, name: str):
... self.name = name
>>> @ino.inject
... def func(thing: Thing):
... return thing.name
>>> # no providers available yet
>>> func()
TypeError: ... missing 1 required positional argument: 'thing'
>>> # register a provider
>>> ino.register(providers={Thing: Thing("Thing1")})
>>> print(func())
'Thing1'
>>> # can still override with parameters
>>> func(Thing("OtherThing"))
'OtherThing'
Source code in in_n_out/_store.py
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 |
|
inject_processors #
inject_processors(func: Callable[P, R] | None = None, *, type_hint: type[T] | object | None = None, first_processor_only: bool = False, raise_exception: bool = False) -> Callable[[Callable[P, R]], Callable[P, R]] | Callable[P, R]
Decorate a function to process its output.
Variant of inject
, but only injects processors
(for the sake of more explicit syntax).
When the decorated function is called, the return value will be processed
with store.process(return_value)
before returning the result.
Important! This means that calling func
will likely have side effects.
Parameters:
-
func
(Callable
, default:None
) –A function to decorate. Return hints are used to determine what to process.
-
type_hint
(type[T] | object | None
, default:None
) –Type hint for the return value. If not provided, the type will be inferred first from the return annotation of the function, and if that is not provided, from the
type(return_value)
. -
first_processor_only
(bool
, default:False
) –If
True
, only the first processor will be invoked, otherwise all processors will be invoked, in descending weight order. -
raise_exception
(bool
, default:False
) –If
True
, and a processor raises an exception, it will be raised and the remaining processors will not be invoked.
Returns:
-
Callable
–A function that, when called, will have its return value processed by
store.process(return_value)
Source code in in_n_out/_store.py
877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 |
|
iter_processors #
iter_processors(type_hint: type[T] | object) -> Iterator[Callable[[T], Any]]
Iterate over all processors of type_hint
.
Parameters:
Yields:
Source code in in_n_out/_store.py
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 |
|
iter_providers #
iter_providers(type_hint: type[T] | object) -> Iterator[Callable[[], T | None]]
Iterate over all providers of type_hint
.
Parameters:
Yields:
Source code in in_n_out/_store.py
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 |
|
mark_processor #
mark_processor(func: ProcessorVar | None = None, *, type_hint: object | None = None, weight: float = 0) -> Callable[[ProcessorVar], ProcessorVar] | ProcessorVar
Decorate func
as a processor of its first parameter type.
Parameters:
-
func
(Processor | None
, default:None
) –A function to decorate. If not provided, a decorator is returned.
-
type_hint
(object | None
, default:None
) –Optional type or type hint that this processor can handle. If not provided, the type hint of the first parameter of
func
will be used. -
weight
(float
, default:0
) –A weight with which to sort this processor. Higher weights are given priority, by default 0. When invoking processors, all processors will be invoked in descending weight order, unless
first_processor_only
is set toTrue
.
Returns:
-
Callable[[Processor], Processor] | Processor
–If
func
is not provided, a decorator is returned, iffunc
is provided then the function is returned.
Examples:
>>> @store.processor
>>> def process_int(x: int) -> None:
... print("Processing int:", x)
Source code in in_n_out/_store.py
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 |
|
mark_provider #
mark_provider(func: ProviderVar | None = None, *, type_hint: object | None = None, weight: float = 0) -> Callable[[ProviderVar], ProviderVar] | ProviderVar
Decorate func
as a provider of its first parameter type.
Note, If func returns Optional[Type]
, it will be registered as a provider
for Type.
Parameters:
-
func
(Provider | None
, default:None
) –A function to decorate. If not provided, a decorator is returned.
-
type_hint
(object | None
, default:None
) –Optional type or type hint for which to register this provider. If not provided, the return annotation of
func
will be used. -
weight
(float
, default:0
) –A weight with which to sort this provider. Higher weights are given priority, by default 0
Returns:
-
Callable[[Provider], Provider] | Provider
–If
func
is not provided, a decorator is returned, iffunc
is provided then the function is returned..
Examples:
>>> @store.provider
>>> def provide_int() -> int:
... return 42
Source code in in_n_out/_store.py
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 |
|
process #
process(result: Any, *, type_hint: type[T] | object | None = None, first_processor_only: bool = False, raise_exception: bool = False, _funcname: str = '') -> None
Process an instance of type_
.
This will iterate over all processors of type_
and invoke the first
one that accepts result
, unless first_processor_only
is set to False
,
in which case all processors will be invoked.
Parameters:
-
result
(Any
) –The result to process
-
type_hint
(type[T] | object | None
, default:None
) –An optional type hint to provide to the processor. If not provided, the type of
result
will be used. -
first_processor_only
(bool
, default:False
) –If
True
, only the first processor will be invoked, otherwise all processors will be invoked, in descending weight order. -
raise_exception
(bool
, default:False
) –If
True
, and a processor raises an exception, it will be raised and the remaining processors will not be invoked. -
_funcname
(str
, default:''
) –The name of the function that called this method. This is used internally for debugging
Source code in in_n_out/_store.py
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 |
|
provide #
provide(type_hint: type[T] | object) -> T | None
Provide an instance of type_hint
.
This will iterate over all providers of type_hint
and return the first
one that returns a non-None
value.
Parameters:
Returns:
-
T | None
–The first non-
None
value returned by a provider, orNone
if no providers return a value.
Source code in in_n_out/_store.py
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 |
|
register #
register(*, providers: ProviderIterable | None = None, processors: ProcessorIterable | None = None) -> InjectionContext
Register multiple providers and/or processors at once.
This may be used as a context manager to temporarily register providers and/or processors.
The format for providers/processors is one of: - a mapping of {type_hint: provider} pairs - an iterable of 1, 2, or 3-tuples, where each tuple in the iterable is: - (callback,) - (callback, type_hint,) - (callback, type_hint, weight)
Parameters:
-
providers
(CallbackIterable | None
, default:None
) –mapping or iterable of providers to register. See format in notes above.
-
processors
(CallbackIterable | None
, default:None
) –mapping or iterable of processors to register. See format in notes above.
Returns:
-
InjectionContext
–Context manager for unregistering providers and processors. If the context is entered with
with store.register(): ...
, then callbacks will be unregistered when the context is exited. Callbacks may also be unregistered manually using the.cleanup()
method of the returned context manager.
Examples:
>>> with store.register(
providers={int: lambda: 42}, # provided as hint->callback map
processors=[
(my_callback), # hint inferred from signature
(my_other_callback, str), # hint explicitly provided
(my_third_callback, int, 10) # weight explicitly provided
],
):
...
Source code in in_n_out/_store.py
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
|
register_processor #
register_processor(processor: Processor, type_hint: object | None = None, weight: float = 0) -> InjectionContext
Register processor
as a processor of type_hint
.
Processors are callbacks that are invoked when an injected function returns
an instance of type_hint
.
Parameters:
-
type_hint
(object
, default:None
) –A type or type hint that
processor
can handle. -
processor
(Callable
) –A processor callback. Must accept at least one argument.
-
weight
(float
, default:0
) –A weight with which to sort this processor. Higher weights are given priority, by default 0. When invoking processors, all processors will be invoked in descending weight order, unless
first_processor_only
is set toTrue
.
Returns:
-
Callable
–A function that unregisters the processor.
Source code in in_n_out/_store.py
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
|
register_provider #
register_provider(provider: Provider, type_hint: object | None = None, weight: float = 0) -> InjectionContext
Register provider
as a provider of type_hint
.
Parameters:
-
provider
(Callable
) –A provider callback. Must be able to accept no arguments.
-
type_hint
(object | None
, default:None
) –A type or type hint that
provider
provides. If not provided, it will be inferred from the return annotation ofprovider
. -
weight
(float
, default:0
) –A weight with which to sort this provider. Higher weights are given priority, by default 0
Returns:
-
Callable
–A function that unregisters the provider.
Source code in in_n_out/_store.py
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
|
inject #
inject(func: Callable[P, R] | None = None, *, providers: bool = True, processors: bool = False, localns: dict | None = None, on_unresolved_required_args: RaiseWarnReturnIgnore | None = None, on_unannotated_required_args: RaiseWarnReturnIgnore | None = None, guess_self: bool | None = None, store: str | Store | None = None) -> Callable[..., R] | Callable[[Callable[P, R]], Callable[..., R]]
Decorate func
to inject dependencies at calltime from store
or the global store.
See Store.inject
for details.
Source code in in_n_out/_global.py
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
|
inject_processors #
inject_processors(func: Callable[P, R] | None = None, *, hint: object | type[T] | None = None, first_processor_only: bool = False, raise_exception: bool = False, store: str | Store | None = None) -> Callable[[Callable[P, R]], Callable[P, R]] | Callable[P, R]
Decorate a function to process its output from store
or the global store.
See Store.inject_processors
for details.
Source code in in_n_out/_global.py
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
|
iter_processors #
iter_processors(type_hint: object | type[T], store: str | Store | None = None) -> Iterable[Callable[[T], Any]]
Iterate over all processors of type_hint
in store
or the global store.
See Store.iter_processors
for details.
Source code in in_n_out/_global.py
182 183 184 185 186 187 188 189 190 |
|
iter_providers #
iter_providers(type_hint: type[T], store: str | Store | None = None) -> Iterable[Callable[[], T | None]]
Iterate over all providers of type_hint
in store
or the global store.
See Store.iter_providers
for details.
Source code in in_n_out/_global.py
171 172 173 174 175 176 177 178 179 |
|
mark_processor #
mark_processor(func: ProcessorVar | None = None, *, weight: float = 0, type_hint: object | None = None, store: str | Store | None = None) -> Callable[[ProcessorVar], ProcessorVar] | ProcessorVar
Decorate func
as a processor in store
or the global store.
See Store.mark_processor
for details.
Source code in in_n_out/_global.py
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
|
mark_provider #
mark_provider(func: ProviderVar | None = None, *, weight: float = 0, type_hint: object | None = None, store: str | Store | None = None) -> Callable[[ProviderVar], ProviderVar] | ProviderVar
Decorate func
as a provider in store
or the global store.
See Store.mark_provider
for details.
Source code in in_n_out/_global.py
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
|
process #
process(result: Any, *, type_hint: object | type[T] | None = None, first_processor_only: bool = False, raise_exception: bool = False, store: str | Store | None = None) -> None
Process an instance of type_
with processors from store
or the global store.
See Store.process
for details.
Source code in in_n_out/_global.py
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
|
provide #
provide(type_hint: type[T], store: str | Store | None = None) -> T | None
Provide an instance of type_hint
with providers from store
or the global store.
See Store.provide
for details.
Source code in in_n_out/_global.py
193 194 195 196 197 198 199 200 201 202 |
|
register #
register(*, processors: ProcessorIterable | None = None, providers: ProviderIterable | None = None, store: str | Store | None = None) -> InjectionContext
Register multiple providers and/or processors in store
or the global store.
See Store.register
for details.
Source code in in_n_out/_global.py
51 52 53 54 55 56 57 58 59 60 61 62 |
|
register_processor #
register_processor(processor: Processor, type_hint: object | None = None, weight: float = 0, store: str | Store | None = None) -> InjectionContext
Register a processor in store
or the global store.
See Store.register_processor
for details.
Source code in in_n_out/_global.py
81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
|
register_provider #
register_provider(provider: Provider, type_hint: object | None = None, weight: float = 0, store: str | Store | None = None) -> InjectionContext
Register a provider in store
or the global store.
See Store.register_provider
for details.
Source code in in_n_out/_global.py
65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
|
resolve_single_type_hints #
resolve_single_type_hints(*objs: Any, globalns: dict | None = None, localns: dict | None = None, include_extras: bool = False) -> tuple[Any, ...]
Get type hints for one or more isolated type annotations.
Wrapper around resolve_type_hints
(see docstring for that function for parameter docs).
typing.get_type_hints
only works for modules, classes,
methods, or functions, but the typing module doesn't make the underlying type
evaluation logic publicly available. This function creates a small mock object with
an __annotations__
dict that will work as an argument to
typing.get_type_hints()
. It then extracts the resolved hints back into a tuple of
hints corresponding to the input objects.
Returns:
Examples:
>>> resolve_single_type_hints("hi", localns={"hi": typing.Any})
(typing.Any,)
Source code in in_n_out/_type_resolution.py
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
|
resolve_type_hints #
resolve_type_hints(obj: _get_type_hints_obj_allowed_types, globalns: dict | None = None, localns: dict | None = None, include_extras: bool = False) -> dict[str, Any]
Return type hints for an object.
This is a small wrapper around typing.get_type_hints()
that adds
namespaces to the global and local namespaces.
see docstring for typing.get_type_hints
.
Parameters:
-
obj
(module, class, method, or function
) –must be a module, class, method, or function.
-
globalns
(dict | None
, default:None
) –optional global namespace, by default None.
-
localns
(dict | None
, default:None
) –optional local namespace, by default None.
-
include_extras
(bool
, default:False
) –If
False
(the default), recursively replaces all 'Annotated[T, ...]' with 'T'.
Returns:
Source code in in_n_out/_type_resolution.py
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
|
type_resolved_signature #
type_resolved_signature(func: Callable, *, localns: dict | None = None, raise_unresolved_optional_args: bool = True, raise_unresolved_required_args: bool = True, guess_self: bool = True) -> Signature
Return a Signature object for a function with resolved type annotations.
Parameters:
-
func
(Callable
) –A callable object.
-
localns
(dict | None
, default:None
) –Optional local namespace for name resolution, by default None
-
raise_unresolved_optional_args
(bool
, default:True
) –Whether to raise an exception when an optional parameter (one with a default value) has an unresolvable type annotation, by default True
-
raise_unresolved_required_args
(bool
, default:True
) –Whether to raise an exception when a required parameter has an unresolvable type annotation, by default True
-
guess_self
(bool
, default:True
) –Whether to infer the type of the first argument if the function is an unbound class method. This is done as follows: - if '.' (but not '
') is in the function's qualname - and if the first parameter is named 'self' or starts with "_" - and if the first parameter annotation is inspect.empty
- then the name precedingfunc.__name__
in the function's qualname (which is usually the class name), is looked up in the function's__globals__
namespace. If found, it is used as the first parameter's type annotation. This allows class methods to be injected with instances of the class.
Returns:
-
Signature
–inspect.Signature
object with fully resolved type annotations, (or at least partially resolved type annotations ifraise_unresolved_optional_args
isFalse
).
Raises:
-
NameError
–If a required argument has an unresolvable type annotation, or if
raise_unresolved_optional_args
isTrue
and an optional argument has an unresolvable type annotation.
Source code in in_n_out/_type_resolution.py
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
|