Skip to content

clone_items: The _deep_get function errors when encountering a str instead of dict #2244

Open
@phaakma

Description

@phaakma

Describe the bug
The clone_items method has a function called _deep_get that it invokes to search for nested values in a dictionary. However, this function assumes that a dict is passed in and that all nested key values are dicts too. In certain circumstances, it encounters a string and throws an error. At this point the cloning method cleans up and deletes the target feature service and therefore the cloning process fails.

To Reproduce
Steps to reproduce the behavior:
This error was encountered when attempting to clone a hosted feature service with views. The stack trace indicated it was something to do with domain values. There were no domains on the fields in the feature service, which likely caused the error by passing in an empty string instead of anticipated domain dict.

error:

("Failed to create Feature Service XXXXXXXX_MMYYYY_WRNA_form: 'str' object has no attribute 'get'", <Item title:"survey123_b0236_fieldworker" type:Feature Layer Collection owner:xxxxxxxx>)

Screenshots

Image

Expected behavior
The clone should succed, regardless of the whether the hosted feature service has views or not, and regardless of whether the base service or the views have domains defined or not.

Platform (please complete the following information):

  • OS: Windows Server 2022 Datacenter
  • Browser: Edge
  • Python API Version: 2.4.0.1

Additional context
The _deep_get method is in this file, right at the very end:
\envs\arcgispro-py3-clone\Lib\site-packages\arcgis\_impl\common\_clone.py

This is the existing function which is flawed:

def _deep_get(dictionary, *keys):
    """Safely return a nested value from a dictionary. If at any point along the path the key doesn't exist the function will return None.
    Keyword arguments:
    dictionary - The dictionary to search for the value
    *keys - The keys used to fetch the desired value"""

    return reduce(lambda d, key: d.get(key) if d else None, keys, dictionary)

I was able to manually edit this file and update the function so that it works as follows:

def _deep_get(dictionary, *keys):
    """Safely return a nested value from a dictionary. If at any point along the path the key doesn't exist the function will return None.
    Keyword arguments:
    dictionary - The dictionary to search for the value
    *keys - The keys used to fetch the desired value"""

    if not isinstance(dictionary, dict):
        return None

    return reduce(lambda d, key: d.get(key) if isinstance(d, dict) else None, keys, dictionary)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions