2828 NamedTuple ,
2929 NoReturn ,
3030 MutableMapping ,
31+ Collection ,
3132 cast ,
3233 overload ,
3334 TYPE_CHECKING
@@ -199,9 +200,16 @@ def __call__(self, *args, **keywords):
199200 return self .func (* args , * self .args , ** keywords )
200201
201202
202- def split_dict (dct : MutableMapping [KT , VT ], keep_keys : Iterable [KT ],
203- keep_order : bool = True ) -> Dict [KT , VT ]:
204- """Pop all items from **dct** which are not in **keep_keys** and use them to construct a new dictionary.
203+ @overload
204+ def split_dict (dct : MutableMapping [KT , VT ], preserve_order : bool = ..., * ,
205+ keep_keys : Iterable [KT ]) -> Dict [KT , VT ]:
206+ ...
207+ @overload # noqa: E302
208+ def split_dict (dct : MutableMapping [KT , VT ], preserve_order : bool = ..., * ,
209+ disgard_keys : Iterable [KT ]) -> Dict [KT , VT ]:
210+ ...
211+ def split_dict (dct : MutableMapping [KT , VT ], preserve_order : bool = False , * , keep_keys : Iterable [KT ] = None , disgard_keys : Iterable [KT ] = None ) -> Dict [KT , VT ]: # noqa: E302,E501
212+ r"""Pop all items from **dct** which are in not in **keep_keys** and use them to construct a new dictionary.
205213
206214 Note that, by popping its keys, the passed **dct** will also be modified inplace.
207215
@@ -214,48 +222,78 @@ def split_dict(dct: MutableMapping[KT, VT], keep_keys: Iterable[KT],
214222 >>> dict1 = {1: 'a', 2: 'b', 3: 'c', 4: 'd'}
215223 >>> dict2 = split_dict(dict1, keep_keys={1, 2})
216224
217- >>> print(dict1)
225+ >>> print(dict1, dict2, sep='\n' )
218226 {1: 'a', 2: 'b'}
219-
220- >>> print(dict2)
221227 {3: 'c', 4: 'd'}
222228
229+ >>> dict3 = split_dict(dict1, disgard_keys={1, 2})
230+ >>> print(dict1, dict3, sep='\n')
231+ {}
232+ {1: 'a', 2: 'b'}
233+
223234 Parameters
224235 ----------
225236 dct : :class:`MutableMapping[KT, VT]<typing.MutableMapping>`
226237 A mutable mapping.
227- keep_keys : :class:`Iterable[KT]<typing.Iterable>`
228- An iterable with keys that should remain in **dct**.
229- keep_order : :class:`bool`
238+ preserve_order : :class:`bool`
230239 If :data:`True`, preserve the order of the items in **dct**.
231- Note that :code:`keep_order = False` is generally faster.
240+ Note that :code:`preserve_order = False` is generally faster.
241+ keep_keys : :class:`Iterable[KT]<typing.Iterable>`, keyword-only
242+ An iterable with keys that should remain in **dct**.
243+ Note that **keep_keys** and **disgard_keys** are mutually exclusive.
244+ disgard_keys : :class:`Iterable[KT]<typing.Iterable>`, keyword-only
245+ An iterable with keys that should be removed from **dct**.
246+ Note that **disgard_keys** and **keep_keys** are mutually exclusive.
232247
233248 Returns
234249 -------
235250 :class:`Dict[KT, VT]<typing.Dict>`
236251 A new dictionaries with all key/value pairs from **dct** not specified in **keep_keys**.
237252
238253 """ # noqa: E501
239- # The ordering of dict elements is preserved in this manner,
240- # as opposed to the use of set.difference()
241- if keep_order :
242- difference : Iterable [KT ] = [k for k in dct if k not in keep_keys ]
254+ if keep_keys is disgard_keys is None :
255+ raise TypeError ("'keep_keys' and 'disgard_keys' cannot both be unspecified" )
256+ elif keep_keys is not None :
257+ iterable = _keep_keys (dct , keep_keys , preserve_order )
258+ elif disgard_keys is not None :
259+ iterable = _disgard_keys (dct , disgard_keys , preserve_order )
260+ else :
261+ raise TypeError ("'keep_keys' and 'disgard_keys' cannot both be specified" )
262+
263+ return {k : dct .pop (k ) for k in iterable }
264+
265+
266+ def _keep_keys (dct : Mapping [KT , VT ], keep_keys : Iterable [KT ],
267+ preserve_order : bool = False ) -> Collection [KT ]:
268+ """A helper function for :func:`split_dict`; used when :code:`keep_keys is not None`."""
269+ if preserve_order :
270+ return [k for k in dct if k not in keep_keys ]
243271 else :
244272 try :
245- difference = dct .keys () - keep_keys # type: ignore
273+ return dct .keys () - keep_keys # type: ignore
246274 except (TypeError , AttributeError ):
247- difference = set (dct .keys ()).difference (keep_keys )
275+ return set (dct .keys ()).difference (keep_keys )
276+
248277
249- return {k : dct .pop (k ) for k in difference }
278+ def _disgard_keys (dct : Mapping [KT , VT ], keep_keys : Iterable [KT ],
279+ preserve_order : bool = False ) -> Collection [KT ]:
280+ """A helper function for :func:`split_dict`; used when :code:`disgard_keys is not None`."""
281+ if preserve_order :
282+ return [k for k in dct if k in keep_keys ]
283+ else :
284+ try :
285+ return dct .keys () + keep_keys # type: ignore
286+ except TypeError :
287+ return set (dct .keys ()).union (keep_keys )
250288
251289
252290@overload
253- def raise_if (ex : None ) -> Callable [[FT ], FT ]:
291+ def raise_if (exception : None ) -> Callable [[FT ], FT ]:
254292 ...
255293@overload # noqa: E302
256- def raise_if (ex : BaseException ) -> Callable [[Callable ], Callable [..., NoReturn ]]:
294+ def raise_if (exception : BaseException ) -> Callable [[Callable ], Callable [..., NoReturn ]]:
257295 ...
258- def raise_if (ex : Optional [BaseException ]) -> Callable : # noqa: E302
296+ def raise_if (exception : Optional [BaseException ]) -> Callable : # noqa: E302
259297 """A decorator which raises the passed exception whenever calling the decorated function.
260298
261299 Examples
@@ -286,24 +324,24 @@ def raise_if(ex: Optional[BaseException]) -> Callable: # noqa: E302
286324
287325 Parameters
288326 ----------
289- ex : :exc:`BaseException`, optional
327+ exception : :exc:`BaseException`, optional
290328 An exception.
291329 If :data:`None` is passed then the decorated function will be called as usual.
292330
293331 """
294- if ex is None :
332+ if exception is None :
295333 def decorator (func : FT ):
296334 return func
297335
298- elif isinstance (ex , BaseException ):
336+ elif isinstance (exception , BaseException ):
299337 def decorator (func : FT ):
300338 @wraps (func )
301339 def wrapper (* args , ** kwargs ):
302- raise ex
340+ raise exception
303341 return wrapper
304342
305343 else :
306- raise TypeError (f"{ ex .__class__ .__name__ !r} " )
344+ raise TypeError (f"{ exception .__class__ .__name__ !r} " )
307345 return decorator
308346
309347
0 commit comments