ominfra 0.0.0.dev124__py3-none-any.whl → 0.0.0.dev125__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,6 +4,34 @@
4
4
  # @omlish-script
5
5
  # @omlish-amalg-output ../supervisor/main.py
6
6
  # ruff: noqa: N802 UP006 UP007 UP012 UP036
7
+ # Supervisor is licensed under the following license:
8
+ #
9
+ # A copyright notice accompanies this license document that identifies the copyright holders.
10
+ #
11
+ # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
12
+ # following conditions are met:
13
+ #
14
+ # 1. Redistributions in source code must retain the accompanying copyright notice, this list of conditions, and the
15
+ # following disclaimer.
16
+ #
17
+ # 2. Redistributions in binary form must reproduce the accompanying copyright notice, this list of conditions, and the
18
+ # following disclaimer in the documentation and/or other materials provided with the distribution.
19
+ #
20
+ # 3. Names of the copyright holders must not be used to endorse or promote products derived from this software without
21
+ # prior written permission from the copyright holders.
22
+ #
23
+ # 4. If any files are modified, you must cause the modified files to carry prominent notices stating that you changed
24
+ # the files and the date of any change.
25
+ #
26
+ # Disclaimer
27
+ #
28
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
29
+ # NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
30
+ # EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33
+ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
34
+ # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7
35
  import abc
8
36
  import base64
9
37
  import collections.abc
@@ -74,6 +102,9 @@ T = ta.TypeVar('T')
74
102
  SocketAddress = ta.Any
75
103
  SocketHandlerFactory = ta.Callable[[SocketAddress, ta.BinaryIO, ta.BinaryIO], 'SocketHandler']
76
104
 
105
+ # ../events.py
106
+ EventCallback = ta.Callable[['Event'], None]
107
+
77
108
  # ../../../omlish/lite/http/parsing.py
78
109
  HttpHeaders = http.client.HTTPMessage # ta.TypeAlias
79
110
 
@@ -92,12 +123,6 @@ HttpHandler = ta.Callable[['HttpHandlerRequest'], 'HttpHandlerResponse']
92
123
  # ../../../omlish/lite/http/coroserver.py
93
124
  CoroHttpServerFactory = ta.Callable[[SocketAddress], 'CoroHttpServer']
94
125
 
95
- # ../context.py
96
- ServerEpoch = ta.NewType('ServerEpoch', int)
97
-
98
- # ../process.py
99
- InheritedFds = ta.NewType('InheritedFds', ta.FrozenSet[int])
100
-
101
126
 
102
127
  ########################################
103
128
  # ../../../omdev/toml/parser.py
@@ -1537,6 +1562,18 @@ class SocketHandler(abc.ABC):
1537
1562
  raise NotImplementedError
1538
1563
 
1539
1564
 
1565
+ ########################################
1566
+ # ../../../omlish/lite/typing.py
1567
+
1568
+
1569
+ @dc.dataclass(frozen=True)
1570
+ class Func(ta.Generic[T]):
1571
+ fn: ta.Callable[..., T]
1572
+
1573
+ def __call__(self, *args: ta.Any, **kwargs: ta.Any) -> T:
1574
+ return self.fn(*args, **kwargs)
1575
+
1576
+
1540
1577
  ########################################
1541
1578
  # ../events.py
1542
1579
 
@@ -1551,9 +1588,6 @@ class Event(abc.ABC): # noqa
1551
1588
  ##
1552
1589
 
1553
1590
 
1554
- EventCallback = ta.Callable[['Event'], None]
1555
-
1556
-
1557
1591
  class EventCallbacks:
1558
1592
  def __init__(self) -> None:
1559
1593
  super().__init__()
@@ -2398,7 +2432,13 @@ class HttpRequestParser:
2398
2432
 
2399
2433
  @dc.dataclass(frozen=True)
2400
2434
  class InjectorKey(ta.Generic[T]):
2401
- cls: InjectorKeyCls
2435
+ # Before PEP-560 typing.Generic was a metaclass with a __new__ that takes a 'cls' arg, so instantiating a dataclass
2436
+ # with kwargs (such as through dc.replace) causes `TypeError: __new__() got multiple values for argument 'cls'`.
2437
+ # See:
2438
+ # - https://github.com/python/cpython/commit/d911e40e788fb679723d78b6ea11cabf46caed5a
2439
+ # - https://gist.github.com/wrmsr/4468b86efe9f373b6b114bfe85b98fd3
2440
+ cls_: InjectorKeyCls
2441
+
2402
2442
  tag: ta.Any = None
2403
2443
  array: bool = False
2404
2444
 
@@ -2519,14 +2559,14 @@ class FnInjectorProvider(InjectorProvider):
2519
2559
 
2520
2560
  @dc.dataclass(frozen=True)
2521
2561
  class CtorInjectorProvider(InjectorProvider):
2522
- cls: type
2562
+ cls_: type
2523
2563
 
2524
2564
  def __post_init__(self) -> None:
2525
- check_isinstance(self.cls, type)
2565
+ check_isinstance(self.cls_, type)
2526
2566
 
2527
2567
  def provider_fn(self) -> InjectorProviderFn:
2528
2568
  def pfn(i: Injector) -> ta.Any:
2529
- return i.inject(self.cls)
2569
+ return i.inject(self.cls_)
2530
2570
 
2531
2571
  return pfn
2532
2572
 
@@ -2675,19 +2715,42 @@ def build_injector_provider_map(bs: InjectorBindings) -> ta.Mapping[InjectorKey,
2675
2715
  # inspection
2676
2716
 
2677
2717
 
2678
- _INJECTION_SIGNATURE_CACHE: ta.MutableMapping[ta.Any, inspect.Signature] = weakref.WeakKeyDictionary()
2718
+ # inspect.signature(eval_str=True) was added in 3.10 and we have to support 3.8, so we have to get_type_hints to eval
2719
+ # str annotations *in addition to* getting the signature for parameter information.
2720
+ class _InjectionInspection(ta.NamedTuple):
2721
+ signature: inspect.Signature
2722
+ type_hints: ta.Mapping[str, ta.Any]
2723
+
2679
2724
 
2725
+ _INJECTION_INSPECTION_CACHE: ta.MutableMapping[ta.Any, _InjectionInspection] = weakref.WeakKeyDictionary()
2680
2726
 
2681
- def _injection_signature(obj: ta.Any) -> inspect.Signature:
2727
+
2728
+ def _do_injection_inspect(obj: ta.Any) -> _InjectionInspection:
2729
+ uw = obj
2730
+ while True:
2731
+ if isinstance(uw, functools.partial):
2732
+ uw = uw.func
2733
+ else:
2734
+ if (uw2 := inspect.unwrap(uw)) is uw:
2735
+ break
2736
+ uw = uw2
2737
+
2738
+ return _InjectionInspection(
2739
+ inspect.signature(obj),
2740
+ ta.get_type_hints(uw),
2741
+ )
2742
+
2743
+
2744
+ def _injection_inspect(obj: ta.Any) -> _InjectionInspection:
2682
2745
  try:
2683
- return _INJECTION_SIGNATURE_CACHE[obj]
2746
+ return _INJECTION_INSPECTION_CACHE[obj]
2684
2747
  except TypeError:
2685
- return inspect.signature(obj)
2748
+ return _do_injection_inspect(obj)
2686
2749
  except KeyError:
2687
2750
  pass
2688
- sig = inspect.signature(obj)
2689
- _INJECTION_SIGNATURE_CACHE[obj] = sig
2690
- return sig
2751
+ insp = _do_injection_inspect(obj)
2752
+ _INJECTION_INSPECTION_CACHE[obj] = insp
2753
+ return insp
2691
2754
 
2692
2755
 
2693
2756
  class InjectionKwarg(ta.NamedTuple):
@@ -2708,20 +2771,20 @@ def build_injection_kwargs_target(
2708
2771
  skip_kwargs: ta.Optional[ta.Iterable[ta.Any]] = None,
2709
2772
  raw_optional: bool = False,
2710
2773
  ) -> InjectionKwargsTarget:
2711
- sig = _injection_signature(obj)
2774
+ insp = _injection_inspect(obj)
2712
2775
 
2713
2776
  seen: ta.Set[InjectorKey] = set(map(as_injector_key, skip_kwargs)) if skip_kwargs is not None else set()
2714
2777
  kws: ta.List[InjectionKwarg] = []
2715
- for p in list(sig.parameters.values())[skip_args:]:
2778
+ for p in list(insp.signature.parameters.values())[skip_args:]:
2716
2779
  if p.annotation is inspect.Signature.empty:
2717
2780
  if p.default is not inspect.Parameter.empty:
2718
2781
  raise KeyError(f'{obj}, {p.name}')
2719
2782
  continue
2720
2783
 
2721
2784
  if p.kind not in (inspect.Parameter.POSITIONAL_OR_KEYWORD, inspect.Parameter.KEYWORD_ONLY):
2722
- raise TypeError(sig)
2785
+ raise TypeError(insp)
2723
2786
 
2724
- ann = p.annotation
2787
+ ann = insp.type_hints.get(p.name, p.annotation)
2725
2788
  if (
2726
2789
  not raw_optional and
2727
2790
  is_optional_alias(ann)
@@ -2746,6 +2809,66 @@ def build_injection_kwargs_target(
2746
2809
  )
2747
2810
 
2748
2811
 
2812
+ ###
2813
+ # injector
2814
+
2815
+
2816
+ _INJECTOR_INJECTOR_KEY: InjectorKey[Injector] = InjectorKey(Injector)
2817
+
2818
+
2819
+ class _Injector(Injector):
2820
+ def __init__(self, bs: InjectorBindings, p: ta.Optional[Injector] = None) -> None:
2821
+ super().__init__()
2822
+
2823
+ self._bs = check_isinstance(bs, InjectorBindings)
2824
+ self._p: ta.Optional[Injector] = check_isinstance(p, (Injector, type(None)))
2825
+
2826
+ self._pfm = {k: v.provider_fn() for k, v in build_injector_provider_map(bs).items()}
2827
+
2828
+ if _INJECTOR_INJECTOR_KEY in self._pfm:
2829
+ raise DuplicateInjectorKeyError(_INJECTOR_INJECTOR_KEY)
2830
+
2831
+ def try_provide(self, key: ta.Any) -> Maybe[ta.Any]:
2832
+ key = as_injector_key(key)
2833
+
2834
+ if key == _INJECTOR_INJECTOR_KEY:
2835
+ return Maybe.just(self)
2836
+
2837
+ fn = self._pfm.get(key)
2838
+ if fn is not None:
2839
+ return Maybe.just(fn(self))
2840
+
2841
+ if self._p is not None:
2842
+ pv = self._p.try_provide(key)
2843
+ if pv is not None:
2844
+ return Maybe.empty()
2845
+
2846
+ return Maybe.empty()
2847
+
2848
+ def provide(self, key: ta.Any) -> ta.Any:
2849
+ v = self.try_provide(key)
2850
+ if v.present:
2851
+ return v.must()
2852
+ raise UnboundInjectorKeyError(key)
2853
+
2854
+ def provide_kwargs(self, obj: ta.Any) -> ta.Mapping[str, ta.Any]:
2855
+ kt = build_injection_kwargs_target(obj)
2856
+ ret: ta.Dict[str, ta.Any] = {}
2857
+ for kw in kt.kwargs:
2858
+ if kw.has_default:
2859
+ if not (mv := self.try_provide(kw.key)).present:
2860
+ continue
2861
+ v = mv.must()
2862
+ else:
2863
+ v = self.provide(kw.key)
2864
+ ret[kw.name] = v
2865
+ return ret
2866
+
2867
+ def inject(self, obj: ta.Any) -> ta.Any:
2868
+ kws = self.provide_kwargs(obj)
2869
+ return obj(**kws)
2870
+
2871
+
2749
2872
  ###
2750
2873
  # binder
2751
2874
 
@@ -2795,7 +2918,7 @@ class InjectorBinder:
2795
2918
  to_key: ta.Any = None,
2796
2919
 
2797
2920
  singleton: bool = False,
2798
- ) -> InjectorBinding:
2921
+ ) -> InjectorBindingOrBindings:
2799
2922
  if obj is None or obj is inspect.Parameter.empty:
2800
2923
  raise TypeError(obj)
2801
2924
  if isinstance(obj, cls._BANNED_BIND_TYPES):
@@ -2825,8 +2948,8 @@ class InjectorBinder:
2825
2948
  elif cls._is_fn(obj) and not has_to:
2826
2949
  to_fn = obj
2827
2950
  if key is None:
2828
- sig = _injection_signature(obj)
2829
- key_cls = check_valid_injector_key_cls(sig.return_annotation)
2951
+ insp = _injection_inspect(obj)
2952
+ key_cls: ta.Any = check_valid_injector_key_cls(check_not_none(insp.type_hints.get('return')))
2830
2953
  key = InjectorKey(key_cls)
2831
2954
  else:
2832
2955
  if to_const is not None:
@@ -2878,67 +3001,21 @@ class InjectorBinder:
2878
3001
 
2879
3002
 
2880
3003
  ###
2881
- # injector
2882
-
2883
-
2884
- _INJECTOR_INJECTOR_KEY: InjectorKey[Injector] = InjectorKey(Injector)
2885
-
2886
-
2887
- class _Injector(Injector):
2888
- def __init__(self, bs: InjectorBindings, p: ta.Optional[Injector] = None) -> None:
2889
- super().__init__()
2890
-
2891
- self._bs = check_isinstance(bs, InjectorBindings)
2892
- self._p: ta.Optional[Injector] = check_isinstance(p, (Injector, type(None)))
2893
-
2894
- self._pfm = {k: v.provider_fn() for k, v in build_injector_provider_map(bs).items()}
2895
-
2896
- if _INJECTOR_INJECTOR_KEY in self._pfm:
2897
- raise DuplicateInjectorKeyError(_INJECTOR_INJECTOR_KEY)
2898
-
2899
- def try_provide(self, key: ta.Any) -> Maybe[ta.Any]:
2900
- key = as_injector_key(key)
2901
-
2902
- if key == _INJECTOR_INJECTOR_KEY:
2903
- return Maybe.just(self)
2904
-
2905
- fn = self._pfm.get(key)
2906
- if fn is not None:
2907
- return Maybe.just(fn(self))
2908
-
2909
- if self._p is not None:
2910
- pv = self._p.try_provide(key)
2911
- if pv is not None:
2912
- return Maybe.empty()
2913
-
2914
- return Maybe.empty()
2915
-
2916
- def provide(self, key: ta.Any) -> ta.Any:
2917
- v = self.try_provide(key)
2918
- if v.present:
2919
- return v.must()
2920
- raise UnboundInjectorKeyError(key)
3004
+ # injection helpers
2921
3005
 
2922
- def provide_kwargs(self, obj: ta.Any) -> ta.Mapping[str, ta.Any]:
2923
- kt = build_injection_kwargs_target(obj)
2924
- ret: ta.Dict[str, ta.Any] = {}
2925
- for kw in kt.kwargs:
2926
- if kw.has_default:
2927
- if not (mv := self.try_provide(kw.key)).present:
2928
- continue
2929
- v = mv.must()
2930
- else:
2931
- v = self.provide(kw.key)
2932
- ret[kw.name] = v
2933
- return ret
2934
3006
 
2935
- def inject(self, obj: ta.Any) -> ta.Any:
2936
- kws = self.provide_kwargs(obj)
2937
- return obj(**kws)
3007
+ def make_injector_factory(
3008
+ factory_cls: ta.Any,
3009
+ factory_fn: ta.Callable[..., T],
3010
+ ) -> ta.Callable[..., Func[T]]:
3011
+ def outer(injector: Injector) -> factory_cls:
3012
+ def inner(*args, **kwargs):
3013
+ return injector.inject(functools.partial(factory_fn, *args, **kwargs))
3014
+ return Func(inner)
3015
+ return outer
2938
3016
 
2939
3017
 
2940
- ###
2941
- # injection helpers
3018
+ ##
2942
3019
 
2943
3020
 
2944
3021
  class Injection:
@@ -2969,6 +3046,12 @@ class Injection:
2969
3046
  def override(cls, p: InjectorBindings, *args: InjectorBindingOrBindings) -> InjectorBindings:
2970
3047
  return injector_override(p, *args)
2971
3048
 
3049
+ # injector
3050
+
3051
+ @classmethod
3052
+ def create_injector(cls, *args: InjectorBindingOrBindings, p: ta.Optional[Injector] = None) -> Injector:
3053
+ return _Injector(as_injector_bindings(*args), p)
3054
+
2972
3055
  # binder
2973
3056
 
2974
3057
  @classmethod
@@ -2986,7 +3069,7 @@ class Injection:
2986
3069
  to_key: ta.Any = None,
2987
3070
 
2988
3071
  singleton: bool = False,
2989
- ) -> InjectorBinding:
3072
+ ) -> InjectorBindingOrBindings:
2990
3073
  return InjectorBinder.bind(
2991
3074
  obj,
2992
3075
 
@@ -3002,11 +3085,15 @@ class Injection:
3002
3085
  singleton=singleton,
3003
3086
  )
3004
3087
 
3005
- # injector
3088
+ # helpers
3006
3089
 
3007
3090
  @classmethod
3008
- def create_injector(cls, *args: InjectorBindingOrBindings, p: ta.Optional[Injector] = None) -> Injector:
3009
- return _Injector(as_injector_bindings(*args), p)
3091
+ def bind_factory(
3092
+ cls,
3093
+ factory_cls: ta.Any,
3094
+ factory_fn: ta.Callable[..., T],
3095
+ ) -> InjectorBindingOrBindings:
3096
+ return cls.bind(make_injector_factory(factory_cls, factory_fn))
3010
3097
 
3011
3098
 
3012
3099
  inj = Injection
@@ -4790,7 +4877,7 @@ class CoroHttpServerSocketHandler(SocketHandler):
4790
4877
  # ../types.py
4791
4878
 
4792
4879
 
4793
- class AbstractServerContext(abc.ABC):
4880
+ class ServerContext(abc.ABC):
4794
4881
  @property
4795
4882
  @abc.abstractmethod
4796
4883
  def config(self) -> ServerConfig:
@@ -4807,12 +4894,24 @@ class AbstractServerContext(abc.ABC):
4807
4894
 
4808
4895
  @property
4809
4896
  @abc.abstractmethod
4810
- def pid_history(self) -> ta.Dict[int, 'AbstractSubprocess']:
4897
+ def pid_history(self) -> ta.Dict[int, 'Process']:
4811
4898
  raise NotImplementedError
4812
4899
 
4813
4900
 
4901
+ # class Dispatcher(abc.ABC):
4902
+ # pass
4903
+ #
4904
+ #
4905
+ # class OutputDispatcher(Dispatcher, abc.ABC):
4906
+ # pass
4907
+ #
4908
+ #
4909
+ # class InputDispatcher(Dispatcher, abc.ABC):
4910
+ # pass
4911
+
4912
+
4814
4913
  @functools.total_ordering
4815
- class AbstractSubprocess(abc.ABC):
4914
+ class Process(abc.ABC):
4816
4915
  @property
4817
4916
  @abc.abstractmethod
4818
4917
  def pid(self) -> int:
@@ -4831,7 +4930,7 @@ class AbstractSubprocess(abc.ABC):
4831
4930
 
4832
4931
  @property
4833
4932
  @abc.abstractmethod
4834
- def context(self) -> AbstractServerContext:
4933
+ def context(self) -> ServerContext:
4835
4934
  raise NotImplementedError
4836
4935
 
4837
4936
  @abc.abstractmethod
@@ -4867,12 +4966,12 @@ class AbstractSubprocess(abc.ABC):
4867
4966
  raise NotImplementedError
4868
4967
 
4869
4968
  @abc.abstractmethod
4870
- def get_dispatchers(self) -> ta.Mapping[int, ta.Any]: # dict[int, Dispatcher]
4969
+ def get_dispatchers(self) -> ta.Mapping[int, ta.Any]: # Dispatcher]:
4871
4970
  raise NotImplementedError
4872
4971
 
4873
4972
 
4874
4973
  @functools.total_ordering
4875
- class AbstractProcessGroup(abc.ABC):
4974
+ class ProcessGroup(abc.ABC):
4876
4975
  @property
4877
4976
  @abc.abstractmethod
4878
4977
  def config(self) -> ProcessGroupConfig:
@@ -4884,12 +4983,48 @@ class AbstractProcessGroup(abc.ABC):
4884
4983
  def __eq__(self, other):
4885
4984
  return self.config.priority == other.config.priority
4886
4985
 
4986
+ @abc.abstractmethod
4987
+ def transition(self) -> None:
4988
+ raise NotImplementedError
4989
+
4990
+ @abc.abstractmethod
4991
+ def stop_all(self) -> None:
4992
+ raise NotImplementedError
4993
+
4994
+ @property
4995
+ @abc.abstractmethod
4996
+ def name(self) -> str:
4997
+ raise NotImplementedError
4998
+
4999
+ @abc.abstractmethod
5000
+ def before_remove(self) -> None:
5001
+ raise NotImplementedError
5002
+
5003
+ @abc.abstractmethod
5004
+ def get_dispatchers(self) -> ta.Mapping[int, ta.Any]: # Dispatcher]:
5005
+ raise NotImplementedError
5006
+
5007
+ @abc.abstractmethod
5008
+ def reopen_logs(self) -> None:
5009
+ raise NotImplementedError
5010
+
5011
+ @abc.abstractmethod
5012
+ def get_unstopped_processes(self) -> ta.List[Process]:
5013
+ raise NotImplementedError
5014
+
5015
+ @abc.abstractmethod
5016
+ def after_setuid(self) -> None:
5017
+ raise NotImplementedError
5018
+
4887
5019
 
4888
5020
  ########################################
4889
5021
  # ../context.py
4890
5022
 
4891
5023
 
4892
- class ServerContext(AbstractServerContext):
5024
+ ServerEpoch = ta.NewType('ServerEpoch', int)
5025
+
5026
+
5027
+ class ServerContextImpl(ServerContext):
4893
5028
  def __init__(
4894
5029
  self,
4895
5030
  config: ServerConfig,
@@ -4903,7 +5038,7 @@ class ServerContext(AbstractServerContext):
4903
5038
  self._poller = poller
4904
5039
  self._epoch = epoch
4905
5040
 
4906
- self._pid_history: ta.Dict[int, AbstractSubprocess] = {}
5041
+ self._pid_history: ta.Dict[int, Process] = {}
4907
5042
  self._state: SupervisorState = SupervisorState.RUNNING
4908
5043
 
4909
5044
  if config.user is not None:
@@ -4936,7 +5071,7 @@ class ServerContext(AbstractServerContext):
4936
5071
  self._state = state
4937
5072
 
4938
5073
  @property
4939
- def pid_history(self) -> ta.Dict[int, AbstractSubprocess]:
5074
+ def pid_history(self) -> ta.Dict[int, Process]:
4940
5075
  return self._pid_history
4941
5076
 
4942
5077
  @property
@@ -5283,7 +5418,7 @@ def check_execv_args(filename, argv, st) -> None:
5283
5418
  class Dispatcher(abc.ABC):
5284
5419
  def __init__(
5285
5420
  self,
5286
- process: AbstractSubprocess,
5421
+ process: Process,
5287
5422
  channel: str,
5288
5423
  fd: int,
5289
5424
  *,
@@ -5302,7 +5437,7 @@ class Dispatcher(abc.ABC):
5302
5437
  return f'<{self.__class__.__name__} at {id(self)} for {self._process} ({self._channel})>'
5303
5438
 
5304
5439
  @property
5305
- def process(self) -> AbstractSubprocess:
5440
+ def process(self) -> Process:
5306
5441
  return self._process
5307
5442
 
5308
5443
  @property
@@ -5357,7 +5492,7 @@ class OutputDispatcher(Dispatcher):
5357
5492
 
5358
5493
  def __init__(
5359
5494
  self,
5360
- process: AbstractSubprocess,
5495
+ process: Process,
5361
5496
  event_type: ta.Type[ProcessCommunicationEvent],
5362
5497
  fd: int,
5363
5498
  **kwargs: ta.Any,
@@ -5566,7 +5701,7 @@ class OutputDispatcher(Dispatcher):
5566
5701
  class InputDispatcher(Dispatcher):
5567
5702
  def __init__(
5568
5703
  self,
5569
- process: AbstractSubprocess,
5704
+ process: Process,
5570
5705
  channel: str,
5571
5706
  fd: int,
5572
5707
  **kwargs: ta.Any,
@@ -5615,31 +5750,26 @@ class InputDispatcher(Dispatcher):
5615
5750
  ##
5616
5751
 
5617
5752
 
5618
- @dc.dataclass(frozen=True)
5619
- class SubprocessFactory:
5620
- fn: ta.Callable[[ProcessConfig, AbstractProcessGroup], AbstractSubprocess]
5753
+ ProcessFactory = ta.NewType('ProcessFactory', Func[Process]) # (config: ProcessConfig, group: ProcessGroup)
5621
5754
 
5622
- def __call__(self, config: ProcessConfig, group: AbstractProcessGroup) -> AbstractSubprocess:
5623
- return self.fn(config, group)
5624
5755
 
5625
-
5626
- class ProcessGroup(AbstractProcessGroup):
5756
+ class ProcessGroupImpl(ProcessGroup):
5627
5757
  def __init__(
5628
5758
  self,
5629
5759
  config: ProcessGroupConfig,
5630
5760
  context: ServerContext,
5631
5761
  *,
5632
- subprocess_factory: SubprocessFactory,
5762
+ process_factory: ProcessFactory,
5633
5763
  ):
5634
5764
  super().__init__()
5635
5765
 
5636
5766
  self._config = config
5637
5767
  self._context = context
5638
- self._subprocess_factory = subprocess_factory
5768
+ self._process_factory = process_factory
5639
5769
 
5640
5770
  self._processes = {}
5641
5771
  for pconfig in self._config.processes or []:
5642
- process = self._subprocess_factory(pconfig, self)
5772
+ process = self._process_factory(pconfig, self)
5643
5773
  self._processes[pconfig.name] = process
5644
5774
 
5645
5775
  @property
@@ -5651,7 +5781,7 @@ class ProcessGroup(AbstractProcessGroup):
5651
5781
  return self._config.name
5652
5782
 
5653
5783
  @property
5654
- def context(self) -> AbstractServerContext:
5784
+ def context(self) -> ServerContext:
5655
5785
  return self._context
5656
5786
 
5657
5787
  def __repr__(self):
@@ -5686,7 +5816,7 @@ class ProcessGroup(AbstractProcessGroup):
5686
5816
  # BACKOFF -> FATAL
5687
5817
  proc.give_up()
5688
5818
 
5689
- def get_unstopped_processes(self) -> ta.List[AbstractSubprocess]:
5819
+ def get_unstopped_processes(self) -> ta.List[Process]:
5690
5820
  return [x for x in self._processes.values() if not x.get_state().stopped]
5691
5821
 
5692
5822
  def get_dispatchers(self) -> ta.Dict[int, Dispatcher]:
@@ -5763,18 +5893,21 @@ class ProcessGroups:
5763
5893
  # ../process.py
5764
5894
 
5765
5895
 
5896
+ InheritedFds = ta.NewType('InheritedFds', ta.FrozenSet[int])
5897
+
5898
+
5766
5899
  ##
5767
5900
 
5768
5901
 
5769
- class Subprocess(AbstractSubprocess):
5902
+ class ProcessImpl(Process):
5770
5903
  """A class to manage a subprocess."""
5771
5904
 
5772
5905
  def __init__(
5773
5906
  self,
5774
5907
  config: ProcessConfig,
5775
- group: AbstractProcessGroup,
5908
+ group: ProcessGroup,
5776
5909
  *,
5777
- context: AbstractServerContext,
5910
+ context: ServerContext,
5778
5911
  event_callbacks: EventCallbacks,
5779
5912
 
5780
5913
  inherited_fds: ta.Optional[InheritedFds] = None,
@@ -5813,7 +5946,7 @@ class Subprocess(AbstractSubprocess):
5813
5946
  return self._pid
5814
5947
 
5815
5948
  @property
5816
- def group(self) -> AbstractProcessGroup:
5949
+ def group(self) -> ProcessGroup:
5817
5950
  return self._group
5818
5951
 
5819
5952
  @property
@@ -5821,7 +5954,7 @@ class Subprocess(AbstractSubprocess):
5821
5954
  return self._config
5822
5955
 
5823
5956
  @property
5824
- def context(self) -> AbstractServerContext:
5957
+ def context(self) -> ServerContext:
5825
5958
  return self._context
5826
5959
 
5827
5960
  @property
@@ -6468,7 +6601,7 @@ class SignalHandler:
6468
6601
  def __init__(
6469
6602
  self,
6470
6603
  *,
6471
- context: ServerContext,
6604
+ context: ServerContextImpl,
6472
6605
  signal_receiver: SignalReceiver,
6473
6606
  process_groups: ProcessGroups,
6474
6607
  ) -> None:
@@ -6520,19 +6653,14 @@ class SignalHandler:
6520
6653
  ##
6521
6654
 
6522
6655
 
6523
- @dc.dataclass(frozen=True)
6524
- class ProcessGroupFactory:
6525
- fn: ta.Callable[[ProcessGroupConfig], ProcessGroup]
6526
-
6527
- def __call__(self, config: ProcessGroupConfig) -> ProcessGroup:
6528
- return self.fn(config)
6656
+ ProcessGroupFactory = ta.NewType('ProcessGroupFactory', Func[ProcessGroup]) # (config: ProcessGroupConfig)
6529
6657
 
6530
6658
 
6531
6659
  class Supervisor:
6532
6660
  def __init__(
6533
6661
  self,
6534
6662
  *,
6535
- context: ServerContext,
6663
+ context: ServerContextImpl,
6536
6664
  poller: Poller,
6537
6665
  process_groups: ProcessGroups,
6538
6666
  signal_handler: SignalHandler,
@@ -6556,7 +6684,7 @@ class Supervisor:
6556
6684
  #
6557
6685
 
6558
6686
  @property
6559
- def context(self) -> ServerContext:
6687
+ def context(self) -> ServerContextImpl:
6560
6688
  return self._context
6561
6689
 
6562
6690
  def get_state(self) -> SupervisorState:
@@ -6603,16 +6731,16 @@ class Supervisor:
6603
6731
  return True
6604
6732
 
6605
6733
  def get_process_map(self) -> ta.Dict[int, Dispatcher]:
6606
- process_map = {}
6734
+ process_map: ta.Dict[int, Dispatcher] = {}
6607
6735
  for group in self._process_groups:
6608
6736
  process_map.update(group.get_dispatchers())
6609
6737
  return process_map
6610
6738
 
6611
- def shutdown_report(self) -> ta.List[Subprocess]:
6612
- unstopped: ta.List[Subprocess] = []
6739
+ def shutdown_report(self) -> ta.List[Process]:
6740
+ unstopped: ta.List[Process] = []
6613
6741
 
6614
6742
  for group in self._process_groups:
6615
- unstopped.extend(group.get_unstopped_processes()) # type: ignore
6743
+ unstopped.extend(group.get_unstopped_processes())
6616
6744
 
6617
6745
  if unstopped:
6618
6746
  # throttle 'waiting for x to die' reports
@@ -6840,8 +6968,8 @@ def bind_server(
6840
6968
 
6841
6969
  inj.bind(get_poller_impl(), key=Poller, singleton=True),
6842
6970
 
6843
- inj.bind(ServerContext, singleton=True),
6844
- inj.bind(AbstractServerContext, to_key=ServerContext),
6971
+ inj.bind(ServerContextImpl, singleton=True),
6972
+ inj.bind(ServerContext, to_key=ServerContextImpl),
6845
6973
 
6846
6974
  inj.bind(EventCallbacks, singleton=True),
6847
6975
 
@@ -6850,21 +6978,10 @@ def bind_server(
6850
6978
  inj.bind(SignalHandler, singleton=True),
6851
6979
  inj.bind(ProcessGroups, singleton=True),
6852
6980
  inj.bind(Supervisor, singleton=True),
6853
- ]
6854
6981
 
6855
- #
6856
-
6857
- def make_process_group_factory(injector: Injector) -> ProcessGroupFactory:
6858
- def inner(group_config: ProcessGroupConfig) -> ProcessGroup:
6859
- return injector.inject(functools.partial(ProcessGroup, group_config))
6860
- return ProcessGroupFactory(inner)
6861
- lst.append(inj.bind(make_process_group_factory))
6862
-
6863
- def make_subprocess_factory(injector: Injector) -> SubprocessFactory:
6864
- def inner(process_config: ProcessConfig, group: AbstractProcessGroup) -> AbstractSubprocess:
6865
- return injector.inject(functools.partial(Subprocess, process_config, group))
6866
- return SubprocessFactory(inner)
6867
- lst.append(inj.bind(make_subprocess_factory))
6982
+ inj.bind_factory(ProcessGroupFactory, ProcessGroupImpl),
6983
+ inj.bind_factory(ProcessFactory, ProcessImpl),
6984
+ ]
6868
6985
 
6869
6986
  #
6870
6987
 
@@ -6933,7 +7050,7 @@ def main(
6933
7050
  inherited_fds=inherited_fds,
6934
7051
  ))
6935
7052
 
6936
- context = injector[ServerContext]
7053
+ context = injector[ServerContextImpl]
6937
7054
  supervisor = injector[Supervisor]
6938
7055
 
6939
7056
  try: