Skip to content

Commit 27ecd67

Browse files
committed
add dedup option to select pipe
1 parent c245b8d commit 27ecd67

File tree

2 files changed

+55
-12
lines changed

2 files changed

+55
-12
lines changed

src/pyff/builtins.py

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,7 @@ def select(req: Plumbing.Request, *opts):
732732
Select a set of EntityDescriptor elements as the working document.
733733
734734
:param req: The request
735-
:param opts: Options - used for select alias
735+
:param opts: Options - see Options below
736736
:return: returns the result of the operation as a working document
737737
738738
Select picks and expands elements (with optional filtering) from the active repository you setup using calls
@@ -779,25 +779,60 @@ def select(req: Plumbing.Request, *opts):
779779
would terminate the plumbing at select if there are no SPs in the local repository. This is useful in
780780
combination with fork for handling multiple cases in your plumbings.
781781
782-
The 'as' keyword allows a select to be stored as an alias in the local repository. For instance
782+
Options are put directly after "select". E.g:
783783
784784
.. code-block:: yaml
785785
786-
- select as /foo-2.0: "!//md:EntityDescriptor[md:IDPSSODescriptor]"
786+
- select as /foo-2.0 dedup True: "!//md:EntityDescriptor[md:IDPSSODescriptor]"
787787
788-
would allow you to use /foo-2.0.json to refer to the JSON-version of all IdPs in the current repository.
789-
Note that you should not include an extension in your "as foo-bla-something" since that would make your
790-
alias invisible for anything except the corresponding mime type.
788+
**Options**
789+
Defaults are marked with (*)
790+
- as <name> : The 'as' keyword allows a select to be stored as an alias in the local repository. For instance
791+
792+
.. code-block:: yaml
793+
794+
- select as /foo-2.0: "!//md:EntityDescriptor[md:IDPSSODescriptor]"
795+
796+
would allow you to use /foo-2.0.json to refer to the JSON-version of all IdPs in the current repository.
797+
Note that you should not include an extension in your "as foo-bla-something" since that would make your
798+
alias invisible for anything except the corresponding mime type.
799+
800+
- dedup <True*|False> : Whether to deduplicate the results by entityID.
801+
802+
Note: When select is used after a load pipe with more than one source, if dedup is set to True
803+
and there are entity properties that may differ from one source to another, these will be squashed
804+
rather than merged.
791805
"""
806+
opt_names = ('as', 'dedup')
807+
if len(opts) % 2 == 0:
808+
_opts = dict(list(zip(opts[::2], opts[1::2])))
809+
else:
810+
_opts = {}
811+
for i in range(0, len(opts), 2):
812+
if opts[i] in opt_names:
813+
_opts[opts[i]] = opts[i + 1]
814+
else:
815+
_opts['as'] = opts[i]
816+
if i + 1 < len(opts):
817+
more_opts = opts[i + 1:]
818+
_opts.update(dict(list(zip(more_opts[::2], more_opts[1::2]))))
819+
break
820+
821+
_opts.setdefault('dedup', "True")
822+
_opts.setdefault('name', req.plumbing.id)
823+
_opts['dedup'] = bool(str2bool(_opts['dedup']))
824+
792825
args = _select_args(req)
793-
name = req.plumbing.id
826+
name = _opts['name']
827+
dedup = _opts['dedup']
828+
794829
if len(opts) > 0:
795830
if opts[0] != 'as' and len(opts) == 1:
796831
name = opts[0]
797832
if opts[0] == 'as' and len(opts) == 2:
798833
name = opts[1]
799834

800-
entities = resolve_entities(args, lookup_fn=req.md.store.select)
835+
entities = resolve_entities(args, lookup_fn=req.md.store.select, dedup=dedup)
801836

802837
if req.state.get('match', None): # TODO - allow this to be passed in via normal arguments
803838

src/pyff/samlmd.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ def filter_or_validate(
402402
return t
403403

404404

405-
def resolve_entities(entities, lookup_fn=None):
405+
def resolve_entities(entities, lookup_fn=None, dedup=True):
406406
"""
407407
408408
:param entities: a set of entities specifiers (lookup is used to find entities from this set)
@@ -416,13 +416,21 @@ def _resolve(m, l_fn):
416416
else:
417417
return l_fn(m)
418418

419-
resolved_entities = dict() # a set won't do since __compare__ doesn't use @entityID
419+
if dedup:
420+
resolved_entities = dict() # a set won't do since __compare__ doesn't use @entityID
421+
else:
422+
resolved_entities = []
420423
for member in entities:
421424
for entity in _resolve(member, lookup_fn):
422425
entity_id = entity.get('entityID', None)
423426
if entity is not None and entity_id is not None:
424-
resolved_entities[entity_id] = entity
425-
return resolved_entities.values()
427+
if dedup:
428+
resolved_entities[entity_id] = entity
429+
else:
430+
resolved_entities.append(entity)
431+
if dedup:
432+
return resolved_entities.values()
433+
return resolved_entities
426434

427435

428436
def entitiesdescriptor(

0 commit comments

Comments
 (0)