Skip to content

diff

Functions:

Name Description
attribute_rule_diff

Get a diff of rules for matching FeatureClasses in the dataset

domain_diff

Get a diff of rules for matching FeatureClasses in the dataset

feature_diff

Get features that are added/removed from source/target

field_diff

Get fields that are added/removed from source/target

layer_diff

Get layers that are added/removed from source/target

table_diff

Get tables that are added/removed/changed from source/target

Attributes:

Name Type Description
Diff

Diff = dict[Literal['added', 'removed', 'updated'], list[str] | list[dict[str, Any]]] module-attribute

attribute_rule_diff(source, target)

Get a diff of rules for matching FeatureClasses in the dataset

Parameters:

Name Type Description Default
source Dataset

The starting point of the delta

required
target Dataset

The ending point of the delta

required

Returns:

Type Description
dict[str, diff]

A Mapping of Features to rules with a delta type

Source code in src/arcpie/diff.py
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
def attribute_rule_diff(source: Dataset, target: Dataset) -> dict[str, Diff]:
    """Get a diff of rules for matching FeatureClasses in the dataset

    Args:
        source (Dataset): The starting point of the delta
        target (Dataset): The ending point of the delta

    Returns:
        (dict[str, diff]): A Mapping of Features to rules with a delta type
    """

    _diffs: dict[str, Diff] = {}
    for fc_name, source_fc in source.feature_classes.items():
        if (target_fc := target.feature_classes.get(fc_name, None)) is not None:
            _diffs.setdefault(fc_name, {})
            _diffs[fc_name]['added'] = [rule for rule in target_fc.attribute_rules.names if rule not in source_fc.attribute_rules.names]
            _diffs[fc_name]['removed'] = [rule for rule in source_fc.attribute_rules.names if rule not in target_fc.attribute_rules.names]
            _diffs[fc_name]['updated'] = [
                rule_name
                for rule_name, rule in source_fc.attribute_rules.rules.items()
                if rule and (t_rule := target_fc.attribute_rules.get(rule_name) )
                and rule['scriptExpression'] != t_rule['scriptExpression']
            ]
    return {k:v for k, v in _diffs.items() if v['added'] or v['removed'] or v['updated']}

domain_diff(source, target)

Get a diff of rules for matching FeatureClasses in the dataset

Parameters:

Name Type Description Default
source Dataset

The starting point of the delta

required
target Dataset

The ending point of the delta

required

Returns:

Type Description
Diff

A domain diff

Source code in src/arcpie/diff.py
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
def domain_diff(source: Dataset, target: Dataset) -> Diff:
    """Get a diff of rules for matching FeatureClasses in the dataset

    Args:
        source (Dataset): The starting point of the delta
        target (Dataset): The ending point of the delta

    Returns:
        (Diff): A domain diff
    """
    _diff: Diff = {}
    _to_check: list[str] = ['codedValues', 'description', 'domainType', 'mergePolicy', 'splitPolicy', 'type']
    _diff['added'] = [d for d in target.domains if d not in source.domains]
    _diff['removed'] = [d for d in source.domains if d not in target.domains]
    _diff['updated'] = [
        {name : changes}
        for name, source_domain in source.domains.items()
        if name in target.domains
        and (changes := {
            attr: f"{getattr(source_domain, attr, None)} -> {getattr(target.domains[name], attr, None)}"
            for attr in _to_check
            if str(getattr(source_domain, attr, None)) != str(getattr(target.domains[name], attr, None))
        })
    ]
    return _diff

feature_diff(source, target)

Get features that are added/removed from source/target

Parameters:

Name Type Description Default
source Dataset

The starting point of the delta

required
target Dataset

The ending point of the delta

required

Returns:

Type Description
Diff

FeatureClass delta

Source code in src/arcpie/diff.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def feature_diff(source: Dataset, target: Dataset) -> Diff:
    """Get features that are added/removed from source/target

    Args:
        source (Dataset): The starting point of the delta
        target (Dataset): The ending point of the delta

    Returns:
        (Diff): FeatureClass delta
    """
    _diff: Diff = {}
    _diff['added'] = list(set(target.feature_classes) - set(source.feature_classes))
    _diff['removed'] = list(set(source.feature_classes) - set(target.feature_classes))
    _diff['updated'] = [
        fc for fc in source.feature_classes
        if fc in target
        and (
            set(target.feature_classes[fc].fields) != set(source.feature_classes[fc].fields)
            or not target.feature_classes[fc].py_types.values() == source.feature_classes[fc].py_types.values()
        ) 
    ]
    return _diff

field_diff(source, target)

Get fields that are added/removed from source/target

Parameters:

Name Type Description Default
source Dataset

The starting point of the delta

required
target Dataset

The ending point of the delta

required

Returns:

Type Description
dict[str, Diff]

A Mapping of feature names to field deltas

Source code in src/arcpie/diff.py
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
def field_diff(source: Dataset, target: Dataset) -> dict[str, Diff]:
    """Get fields that are added/removed from source/target

    Args:
        source (Dataset): The starting point of the delta
        target (Dataset): The ending point of the delta

    Returns:
        (dict[str, Diff]): A Mapping of feature names to field deltas
    """
    _diffs: dict[str, Diff] = {}
    for fc_name, source_fc in source.feature_classes.items():
        if (target_fc := target.feature_classes.get(fc_name, None)) is not None:
            _diffs.setdefault(fc_name, {})
            _diffs[fc_name]['added'] = [f for f in target_fc.fields if f not in source_fc.fields]
            _diffs[fc_name]['removed'] = [f for f in source_fc.fields if f not in target_fc.fields]

            # Compare fields from matching features
            _to_compare = ('baseName', 'aliasName', 'defaultValue', 'domain', 
                           'editable', 'isNullable', 'length', 'name', 
                           'precision', 'required', 'scale', 'type')
            _source_fields = {f.baseName: f for f in source_fc.describe.fields}
            _target_fields = {f.baseName: f for f in target_fc.describe.fields}
            _diffs[fc_name]['updated'] = [
                {f : changes} 
                for f in _source_fields
                if f in _target_fields
                and (changes := {
                    attr: f"{getattr(_source_fields[f], attr)} -> {getattr(_target_fields[f], attr)}"
                    for attr in _to_compare
                    if getattr(_source_fields[f], attr) != getattr(_target_fields[f], attr)
                })
            ]

    return {k:v for k, v in _diffs.items() if v['added'] or v['removed'] or v['updated']}

layer_diff(source, target)

Get layers that are added/removed from source/target

Parameters:

Name Type Description Default
source Project

The starting point of the delta

required
target Project

The ending point of the delta

required

Returns:

Type Description
dict[str, Diff]

A Mapping of map names to layer deltas

Source code in src/arcpie/diff.py
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
def layer_diff(source: Project, target: Project) -> dict[str, Diff]:
    """Get layers that are added/removed from source/target

    Args:
        source (Project): The starting point of the delta
        target (Project): The ending point of the delta

    Returns:
        (dict[str, Diff]): A Mapping of map names to layer deltas
    """
    _diffs: dict[str, Diff] = {}
    for source_map in source.maps:
        map_name = source_map.unique_name
        if (target_map := target.maps.get(source_map.unique_name, None)) is not None:
            _diffs.setdefault(map_name, {})
            _diffs[map_name]['added'] = list(set(target_map.layers.names) - set(source_map.layers.names))
            _diffs[map_name]['removed'] = list(set(source_map.layers.names) - set(target_map.layers.names))
            _diffs[map_name]['updated'] = [
                l.unique_name for l in source_map.layers
                if hasattr(l, 'name') 
                and l.unique_name in target_map.layers.names
                and (source_cim := l.cim_dict)
                and (target_cim := target_map.layers[l.unique_name].cim_dict)
                and any(
                    str(source_cim.get(k, 'Source')) != str(target_cim.get(k, 'Target'))
                    for k in ['renderer', 'labelClasses'] # Only compare symbology and labels
                )
            ]
    return {k:v for k, v in _diffs.items() if v['added'] or v['removed'] or v['updated']}

table_diff(source, target)

Get tables that are added/removed/changed from source/target

Parameters:

Name Type Description Default
source Project

The starting point of the delta

required
target Project

The ending point of the delta

required

Returns:

Type Description
dict[str, Diff]

A Mapping of map names to table deltas

Source code in src/arcpie/diff.py
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
def table_diff(source: Project, target: Project) -> dict[str, Diff]:
    """Get tables that are added/removed/changed from source/target

    Args:
        source (Project): The starting point of the delta
        target (Project): The ending point of the delta

    Returns:
        (dict[str, Diff]): A Mapping of map names to table deltas
    """
    _diffs: dict[str, Diff] = {}
    for source_map in source.maps:
        map_name = source_map.unique_name
        if (target_map := target.maps.get(source_map.unique_name, None)) is not None:
            _diffs.setdefault(map_name, {})
            _diffs[map_name]['added'] = list(set(target_map.tables.names) - set(source_map.tables.names))
            _diffs[map_name]['removed'] = list(set(source_map.tables.names) - set(target_map.tables.names))
            _diffs[map_name]['updated'] = [
                t.unique_name for t in source_map.tables
                if hasattr(t, 'name') 
                and t.unique_name in target_map.tables.names
                and (source_cim := t.cim_dict)
                and (target_cim := target_map.tables[t.unique_name].cim_dict)
                and any(
                    str(source_cim.get(k, 'Source')) != str(target_cim.get(k, 'Target'))
                    for k in ['displayField'] # Only compare display field
                )
            ]
    return {k:v for k, v in _diffs.items() if v['added'] or v['removed'] or v['updated']}