pycontribs / jira

Python Jira library. Development chat available on https://matrix.to/#/#pycontribs:matrix.org
https://jira.readthedocs.io
BSD 2-Clause "Simplified" License
1.91k stars 856 forks source link

dict2resource function can create attributes with space in name #1865

Open KarolTracz opened 1 month ago

KarolTracz commented 1 month ago

Bug summary

When dict2resource function is called and one of field name contain space in it, this make the attribute have a space in it also. As a result it is not callable. As a example XRAY plugin for Jira as default use schema that contain name ' expected result'. This result in getting value from this field is not possible.
default schema for test step in XRAY: { "fields":{ "customfield_10004":{ "steps":[ { "index":1, "fields":{ "action":"Step 1", "data":"input Data 1", "expected result":"Excepted result 1" } }, { "index":2, "fields":{ "action":"Step 2", "data":"input Data 2", "expected result":"Excepted result 2" } }, { "index":3, "fields":{ "action":"Step 4", "data":"input Data 3", "expected result":"Excepted result 3" } } ] } } }

Is there an existing issue for this?

Jira Instance type

Jira Cloud (Hosted by Atlassian)

Jira instance version

No response

jira-python version

3.8.0

Python Interpreter version

3.11

Which operating systems have you used?

Reproduction steps

valid_response = {
   "fields":{
      "customfield_10004":{
         "steps":[
            {
               "index":1,
               "fields":{
                  "action":"Step 1",
                  "data":"input Data 1",
                  "expected result":"Excepted result 1"
               }
            },
            {
               "index":2,
               "fields":{
                  "action":"Step 2",
                  "data":"input Data 2",
                  "expected result":"Excepted result 2"
               }
            },
            {
               "index":3,
               "fields":{
                  "action":"Step 4",
                  "data":"input Data 3",
                  "expected result":"Excepted result 3"
               }
            }
         ]
      }
   }
}
from jira.resources import dict2resource

resource_object = dict2resource(valid_response)
for i in resource_object.fields.customfield_10004.steps:
    print(i.fields.action)
    print(i.fields.data)
    print(i.fields.expected_result)

Stack trace

Traceback (most recent call last):
  File "C:\Users\path\to\file\file.py", line 39, in <module>
    print(i.fields.expected_result)
          ^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'PropertyHolder' object has no attribute 'expected_result'. Did you mean: 'expected result'?

Expected behaviour

dict2resource function replace space character in names to underscore or concatenate into one string.

Fix proposal

I assume something like this should work:

def replace_spaces_in_keys(data: Dict[str, Any]) -> Dict[str, Any]:
    if isinstance(data, dict):
        return {replace_spaces_in_strings(k): replace_spaces_in_strings(v) for k, v in data.items()}
    elif isinstance(data, list):
        return [replace_spaces_in_strings(elem) for elem in data]
    elif isinstance(data, str):
        return data.replace(" ", "_")
    else:
        return data

def dict2resource(
    raw: dict[str, Any], top=None, options=None, session=None
) -> PropertyHolder | type[Resource]:
    """Convert a dictionary into a Jira Resource object.

    Recursively walks a dict structure, transforming the properties into attributes on a new ``Resource`` object of the appropriate type
    (if a ``self`` link is present) or a ``PropertyHolder`` object (if no ``self`` link is present).
    """
    if top is None:
        top = PropertyHolder()

    raw = replace_spaces_in_keys(raw)
    [...]

I don't have time to investigate it deeply and create PR. Works locally for me.

Additional Context

I got XRAY test steps schema from https://docs.getxray.app/display/XRAY/Tests+-+REST