pydrepr/drepr/patches/jp_propname_patch.py
def patch(repr: DRepr, _resources: Dict[str, ResourceData]) -> DRepr:
    """
    This patch will fix json path that select property names, before we officially support
    selecting property names

    How does it work: it creates a preprocessing function that convert an object to list of key-value pairs
    """
    need_patch = False
    for pfunc in repr.preprocessing:
        for step in pfunc.value.path.steps:
            if step == WildcardExpr.Names:
                raise Exception(
                    "Does not support preprocessing that is applied on properties of an object yet!"
                )

    for attr in repr.attrs:
        n_wildcard_names = sum(int(step == WildcardExpr.Names) for step in attr.path.steps)
        if n_wildcard_names > 1:
            # cannot select names inside names
            raise Exception(f"Invalid path for attribute {attr.id}")

        if n_wildcard_names > 0:
            need_patch = True

    if need_patch:
        repr = copy.deepcopy(repr)

        # first, find paths that containing the WildcardExpr.Names (*~)
        property_paths = []
        for attr in repr.attrs:
            for i, step in enumerate(attr.path.steps):
                if step == WildcardExpr.Names:
                    property_paths.append((attr.id, i, attr.path.steps[:i]))
                    break

        # now we need to make sure for every property paths, all paths that is overlap to the property paths,
        # need to be exactly equal and no property paths that is subpath of another property path
        for i in range(len(property_paths)):
            for j in range(i + 1, len(property_paths)):
                if is_path_overlap(property_paths[i][-1], property_paths[j][-1]):
                    raise Exception(
                        f"Does not handle nested selecting property names yet. Found in either {property_paths[i][0]} or {property_paths[j][0]}"
                    )

        overlapped_paths = defaultdict(lambda: [])
        for attr in repr.attrs:
            steps = attr.path.steps
            for i, (paid, _, path) in enumerate(property_paths):
                if len(steps) > len(path) and is_path_overlap(path, steps):
                    assert steps[:len(path)] == path, f"Slices {steps} does not fully contain {path}"
                    overlapped_paths[i].append(attr.id)
        # add preprocessing functions
        id2attr = {attr.id: attr for attr in repr.attrs}
        for paid, _, path in property_paths:
            # need to convert dict to key-value pairs
            repr.preprocessing.append(Preprocessing(
                PreprocessingType.rmap,
                RMap(id2attr[paid].resource_id, Path(path), RMapFunc.Dict2Items)
            ))

        # now every property path is distinct, and we have a map of property path => attributes
        # that require to re-map their positions
        for pi, aids in overlapped_paths.items():
            _, _, path = property_paths[pi]
            for aid in aids:
                # remap attribute slices
                attr = id2attr[aid]
                steps = attr.path.steps

                if steps[len(path)] == WildcardExpr.Names:
                    # this select property names
                    steps = steps[:len(path)] + [RangeExpr(0, None, 1), IndexExpr(0)] + steps[len(path) + 1:]
                else:
                    assert steps[len(
                        path
                    )] == WildcardExpr.Values, 'Does not support select both all property names and just a subset of its values'
                    steps = steps[:len(path)] + [RangeExpr(0, None, 1), IndexExpr(1)] + steps[len(path) + 1:]
                attr.path.steps = steps

                # remap alignments
                for alignment in repr.aligns:
                    if isinstance(alignment, RangeAlignment):
                        if alignment.source == aid:
                            for adim in alignment.aligned_steps:
                                if adim.source_idx > len(path):
                                    adim.source_idx += 1
                        elif alignment.target == aid:
                            for adim in alignment.aligned_steps:
                                if adim.target_idx > len(path):
                                    adim.target_idx += 1

    return repr

    This patch will fix json path that select property names, before we officially support
    selecting property names

    How does it work: it creates a preprocessing function that convert an object to list of key-value pairs
    
This patch will fix json path that select property names, before we officially support
selecting property names


This patch will fix json path that select property names before we officially support selecting property names
def patch(repr: DRepr, _resources: Dict[str, ResourceData]) -> DRepr:
    need_patch = False
    for pfunc in repr.preprocessing:
        for step in pfunc.value.path.steps:
            if step == WildcardExpr.Names:
                raise Exception(
                    "Does not support preprocessing that is applied on properties of an object yet!"
                )
    for attr in repr.attrs:
        n_wildcard_names = sum(int(step == WildcardExpr.Names) for step in attr.path.steps)
        if n_wildcard_names > 1:
            raise Exception(f"Invalid path for attribute {attr.id}")
        if n_wildcard_names > 0:
            need_patch = True
    if need_patch:
        repr = copy.deepcopy(repr)
        property_paths = []
        for attr in repr.attrs:
            for i, step in enumerate(attr.path.steps):
                if step == WildcardExpr.Names:
                    property_paths.append((attr.id, i, attr.path.steps[:i]))
                    break
        for i in range(len(property_paths)):
            for j in range(i + 1, len(property_paths)):
                if is_path_overlap(property_paths[i][-1], property_paths[j][-1]):
                    raise Exception(
                        f"Does not handle nested selecting property names yet. Found in either {property_paths[i][0]} or {property_paths[j][0]}"
                    )
        overlapped_paths = defaultdict(lambda: [])
        for attr in repr.attrs:
            steps = attr.path.steps
            for i, (paid, _, path) in enumerate(property_paths):
                if len(steps) > len(path) and is_path_overlap(path, steps):
                    assert steps[:len(path)] == path, f"Slices {steps} does not fully contain {path}"
                    overlapped_paths[i].append(attr.id)
        id2attr = {attr.id: attr for attr in repr.attrs}
        for paid, _, path in property_paths:
            repr.preprocessing.append(Preprocessing(
                PreprocessingType.rmap,
                RMap(id2attr[paid].resource_id, Path(path), RMapFunc.Dict2Items)
            ))
        for pi, aids in overlapped_paths.items():
            _, _, path = property_paths[pi]
            for aid in aids:
                attr = id2attr[aid]
                steps = attr.path.steps
                if steps[len(path)] == WildcardExpr.Names:
                    steps = steps[:len(path)] + [RangeExpr(0, None, 1), IndexExpr(0)] + steps[len(path) + 1:]
                else:
                    assert steps[len(
                        path
                    )] == WildcardExpr.Values, 'Does not support select both all property names and just a subset of its values'
                    steps = steps[:len(path)] + [RangeExpr(0, None, 1), IndexExpr(1)] + steps[len(path) + 1:]
                attr.path.steps = steps
                for alignment in repr.aligns:
                    if isinstance(alignment, RangeAlignment):
                        if alignment.source == aid:
                            for adim in alignment.aligned_steps:
                                if adim.source_idx > len(path):
                                    adim.source_idx += 1
                        elif alignment.target == aid:
                            for adim in alignment.aligned_steps:
                                if adim.target_idx > len(path):
                                    adim.target_idx += 1
    return repr
def patch ( repr : DRepr , _resources : Dict [ str , ResourceData ] ) -> DRepr : need_patch = False for pfunc in repr . preprocessing : for step in pfunc . value . path . steps : if step == WildcardExpr . Names : raise Exception ( "Does not support preprocessing that is applied on properties of an object yet!" ) for attr in repr . attrs : n_wildcard_names = sum ( int ( step == WildcardExpr . Names ) for step in attr . path . steps ) if n_wildcard_names > 1 : raise Exception ( f"Invalid path for attribute {attr.id}" ) if n_wildcard_names > 0 : need_patch = True if need_patch : repr = copy . deepcopy ( repr ) property_paths = [ ] for attr in repr . attrs : for i , step in enumerate ( attr . path . steps ) : if step == WildcardExpr . Names : property_paths . append ( ( attr . id , i , attr . path . steps [ : i ] ) ) break for i in range ( len ( property_paths ) ) : for j in range ( i + 1 , len ( property_paths ) ) : if is_path_overlap ( property_paths [ i ] [ - 1 ] , property_paths [ j ] [ - 1 ] ) : raise Exception ( f"Does not handle nested selecting property names yet. Found in either {property_paths[i][0]} or {property_paths[j][0]}" ) overlapped_paths = defaultdict ( lambda : [ ] ) for attr in repr . attrs : steps = attr . path . steps for i , ( paid , _ , path ) in enumerate ( property_paths ) : if len ( steps ) > len ( path ) and is_path_overlap ( path , steps ) : assert steps [ : len ( path ) ] == path , f"Slices {steps} does not fully contain {path}" overlapped_paths [ i ] . append ( attr . id ) id2attr = { attr . id : attr for attr in repr . attrs } for paid , _ , path in property_paths : repr . preprocessing . append ( Preprocessing ( PreprocessingType . rmap , RMap ( id2attr [ paid ] . resource_id , Path ( path ) , RMapFunc . Dict2Items ) ) ) for pi , aids in overlapped_paths . items ( ) : _ , _ , path = property_paths [ pi ] for aid in aids : attr = id2attr [ aid ] steps = attr . path . steps if steps [ len ( path ) ] == WildcardExpr . Names : steps = steps [ : len ( path ) ] + [ RangeExpr ( 0 , None , 1 ) , IndexExpr ( 0 ) ] + steps [ len ( path ) + 1 : ] else : assert steps [ len ( path ) ] == WildcardExpr . Values , 'Does not support select both all property names and just a subset of its values' steps = steps [ : len ( path ) ] + [ RangeExpr ( 0 , None , 1 ) , IndexExpr ( 1 ) ] + steps [ len ( path ) + 1 : ] attr . path . steps = steps for alignment in repr . aligns : if isinstance ( alignment , RangeAlignment ) : if alignment . source == aid : for adim in alignment . aligned_steps : if adim . source_idx > len ( path ) : adim . source_idx += 1 elif alignment . target == aid : for adim in alignment . aligned_steps : if adim . target_idx > len ( path ) : adim . target_idx += 1 return repr
This patch will fix json path that select property names, before we officially support
selecting property names
This patch will fix json path that select property names before we officially support selecting property names
"""
    This patch will fix json path that select property names, before we officially support
    selecting property names

    How does it work: it creates a preprocessing function that convert an object to list of key-value pairs
    """ # cannot select names inside names # first, find paths that containing the WildcardExpr.Names (*~) # now we need to make sure for every property paths, all paths that is overlap to the property paths, # need to be exactly equal and no property paths that is subpath of another property path # add preprocessing functions # need to convert dict to key-value pairs # now every property path is distinct, and we have a map of property path => attributes # that require to re-map their positions # remap attribute slices # this select property names # remap alignments
repr
DRepr
_resources
Dict[str, ResourceData]