11from collections .abc import MutableMapping , MutableSequence
2+ from enum import Flag , IntFlag , auto
3+ from typing import Union , List , Any , Dict
24
35import dpath .segments
46from dpath import options
57from dpath .exceptions import InvalidKeyName
68
79_DEFAULT_SENTINEL = object ()
8- MERGE_REPLACE = (1 << 1 )
9- MERGE_ADDITIVE = (1 << 2 )
10- MERGE_TYPESAFE = (1 << 3 )
1110
1211
13- def __safe_path__ (path , separator ):
12+ class MergeType (IntFlag ):
13+ REPLACE = auto ()
14+ ADDITIVE = auto ()
15+ TYPESAFE = auto ()
16+
17+
18+ # Type alias for dict path segments where integers are explicitly casted
19+ IntAwareSegment = Union [int , Any ]
20+
21+
22+ def __safe_path__ (path : str , separator : str ) -> Union [List [IntAwareSegment ], IntAwareSegment ]:
1423 """
1524 Given a path and separator, return a tuple of segments. If path is
1625 already a non-leaf thing, return it.
@@ -146,7 +155,7 @@ def f(obj, pair, counter):
146155 return changed
147156
148157
149- def get (obj , glob , separator = '/' , default = _DEFAULT_SENTINEL ):
158+ def get (obj : Dict , glob : str , separator = "/" , default : Any = _DEFAULT_SENTINEL ) -> dict :
150159 """
151160 Given an object which contains only one possible match for the given glob,
152161 return the value for the leaf matching the given glob.
@@ -156,7 +165,7 @@ def get(obj, glob, separator='/', default=_DEFAULT_SENTINEL):
156165 If more than one leaf matches the glob, ValueError is raised. If the glob is
157166 not found and a default is not provided, KeyError is raised.
158167 """
159- if glob == '/' :
168+ if glob == "/" :
160169 return obj
161170
162171 globlist = __safe_path__ (glob , separator )
@@ -233,7 +242,7 @@ def f(obj, pair, result):
233242 return dpath .segments .fold (obj , f , {})
234243
235244
236- def merge (dst , src , separator = '/' , afilter = None , flags = MERGE_ADDITIVE ):
245+ def merge (dst , src , separator = '/' , afilter = None , flags = MergeType . ADDITIVE ):
237246 """
238247 Merge source into destination. Like dict.update() but performs deep
239248 merging.
@@ -262,14 +271,13 @@ def merge(dst, src, separator='/', afilter=None, flags=MERGE_ADDITIVE):
262271 objects that you intend to merge. For further notes see
263272 https://github.com/akesterson/dpath-python/issues/58
264273
265- flags is an OR'ed combination of MERGE_ADDITIVE, MERGE_REPLACE,
266- MERGE_TYPESAFE.
267- * MERGE_ADDITIVE : List objects are combined onto one long
274+ flags is an OR'ed combination of MergeType enum members.
275+ * ADDITIVE : List objects are combined onto one long
268276 list (NOT a set). This is the default flag.
269- * MERGE_REPLACE : Instead of combining list objects, when
277+ * REPLACE : Instead of combining list objects, when
270278 2 list objects are at an equal depth of merge, replace
271279 the destination with the source.
272- * MERGE_TYPESAFE : When 2 keys at equal levels are of different
280+ * TYPESAFE : When 2 keys at equal levels are of different
273281 types, raise a TypeError exception. By default, the source
274282 replaces the destination in this situation.
275283 """
@@ -295,7 +303,7 @@ def merger(dst, src, _segments=()):
295303 "{}" .format (segments ))
296304
297305 # Validate src and dst types match.
298- if flags & MERGE_TYPESAFE :
306+ if flags & MergeType . TYPESAFE :
299307 if dpath .segments .has (dst , segments ):
300308 target = dpath .segments .get (dst , segments )
301309 tt = type (target )
@@ -332,11 +340,11 @@ def merger(dst, src, _segments=()):
332340 #
333341 # Pretend we have a sequence and account for the flags.
334342 try :
335- if flags & MERGE_ADDITIVE :
343+ if flags & MergeType . ADDITIVE :
336344 target += found
337345 continue
338346
339- if flags & MERGE_REPLACE :
347+ if flags & MergeType . REPLACE :
340348 try :
341349 target ['' ]
342350 except TypeError :
0 commit comments