0

I am trying to write a github webhood applicaton. And at one point I will need to access the url to get the json object that loooks like in the picture below, and then I want to convert the "comment" json file into dictionary, so I can easily find the key and values in dictionary.

But the return value from the "json.loads(requests.get(comment_url).text)" is a list, not dictionary, so I have runtime error when I run the code when I was to use it like dictionary.

I googled a lot on this topic, and also try a lot of recommended suggestion from stackoverflow, but haven't found anything yet.

Just wondering does any know how to make the return value from list to dictionary. And I also I thought json.loads should return dictionary instead of list, have I done anything wrong?

comment_url = "https://api.github.com/repos/octocat/Hello-World/pulls/comments/1"

pull_request_comment = json.loads(requests.get(comment_url).text)

polite_words = ("please", "appreciate", "would be great")

for word in polite_words:  # Loop through each element of reportTuple
        if word[0] in pull_request_comment["body"] or word[1]==pull_request_comment["body"] or word[2] ==pull_request_comment["body"]:
                print("You are polite!!!" )
                return 'ok'
        else:
                print("You are impolite!!" )
                return 'skipped'

Error

if word[0] in pull_request_comment["body"]
or word[1]==pull_request_comment["body"] or word[2]
==pull_request_comment["body"]: TypeError: 
list indices must be integers or slices, not str

enter image description here

sample content from the url

enter image description here

Edo Akse
  • 4,051
  • 2
  • 10
  • 21
bbq123
  • 43
  • 8
  • Post your actual code. `word` var isn't defined and the example url you posted 404s. I'm guessing from the error you called `pulls/comments/` (which returns a list of comments) instead of `pulls/comments/{comment_id}`. – flakes Jun 14 '22 at 05:18
  • another note, you can pull the json directly from the response. See [this answer](https://stackoverflow.com/a/16877561/9267296) for example... – Edo Akse Jun 14 '22 at 08:06
  • @flakes I have added the missing line of code, it just loop through the tuple . The actual url is getting from github event by listening the webhook, and only the repo owner can access it. – bbq123 Jun 14 '22 at 08:40
  • @EdoAkse I tried your answer, but it still give me the same error "if word[0] in pull_request_comment["body"] or word[1]==pull_request_comment["body"] or word[2] ==pull_request_comment["body"]: TypeError: list indices must be integers or slices, not str," if I want to access each element in json object, I still need to use json.loads to convert json file into dictionaary, then I will only can get access to the value inside each json element – bbq123 Jun 14 '22 at 08:56

1 Answers1

0

So a couple of things here.

The Github API will return a JSON. From the possible response available here it will not provide a list, but a dict (after conversion from JSON to a python object). I think flakes was correct in his comment.

As to your main issue, I think it has to do with the fact that you use word[0] and word[1]. You are slicing a simple string here. Because of the for loop, each word variable will contain one of the elements from the polite_words. There's no need to actually do any slicing here.

Take a look at the logic below, it will trigger on any comment that contains one of the strings in the polite_words variable.

Also note that if you need the JSON from a request, using the requests library, you can just use response.json(). See the assertion in the logic below. Do please note that I'm doing the simplest assertion to determine if the JSON values are the same.

import json
import requests


comment_url = "https://api.github.com/repos/octocat/Hello-World/pulls/comments/1"

resp = requests.get(comment_url)
text = resp.text
js = resp.json()
print(type(text), text)
print(type(js), js)
pull_request_comment = json.loads(text)
print(type(pull_request_comment), pull_request_comment)

# assert if the values from js and pull_request_comment are the same
assert json.dumps(js, sort_keys=True) == json.dumps(pull_request_comment, sort_keys=True)


polite_words = ("please", "appreciate", "would be great")


# safety check to see if we actually got a body
if "body" in pull_request_comment:
    polite = False
    for word in polite_words:  # Loop through each element of reportTuple
        if word in pull_request_comment["body"]:
            polite = True
            break  # no need for further processing
    if polite:
        print("You are polite!!!")
    else:
        print("You are impolite!!!")
else:
    print(f"no body found in response:\n{text}")

EDIT

So changing the processing of single comments into a function, and then doing a simple check on whether you got a list or a dict (after conversion) from the API, you can call the funcion based on that.

See the adjusted code below...

import json
import requests

polite_words = ("please", "appreciate", "would be great")

def process_comment(comment_dict: dict):
    # safety check to see if we actually got a body
    if "body" in comment_dict:
        polite = False
        for word in polite_words:  # Loop through each element of reportTuple
            if word in comment_dict["body"]:
                polite = True
                break  # no need for further processing
        if polite:
            return "You are polite!!!"
        else:
            return "You are impolite!!!"
    else:
        return f"no body found in response:\n{text}"


comment_url = "https://api.github.com/repos/octocat/Hello-World/pulls/comments/1"
resp_json = requests.get(comment_url).json()
results = []

if type(resp_json) == dict:
    results.append(process_comment(resp_json))
elif type(resp_json) == list:
    results.extend([process_comment(elem) for elem in resp_json])
else:
    print(f"unexpected return from API:\n{resp_json}")

print(results)

To actually answer your question about how JSON is converted, it depends. Both a list and a dict are valid JSON objects. The only thing that the library does, is to make python objects from JSON representations. As to what actually is a valid JSON, the actual RFC8259 has the full spec for it.

In that regard, this works:

huh = json.loads('"value"')
print(huh)

output

value
Edo Akse
  • 4,051
  • 2
  • 10
  • 21
  • Hi, I just noticed the actual value that return from url consist of few json objects [ { "created_at": "2022-06-13T22:10:21Z", "updated_at": "2022-06-13T22:10:21Z", "author_association": "NONE", "body": "want to merge again! " }, { "created_at": "2022-06-13T22:10:21Z", "updated_at": "2022-06-13T22:10:21Z", "author_association": "NONE", "body": "want to merge again! " } ], and the json.loadscan only convert a single object , that's why it get converted to the list. – bbq123 Jun 14 '22 at 13:59
  • which exact URL are you calling? (obfuscate the owner/repo part of the URL) I still think you're calling `https://api.github.com/repos/octocat/Hello-World/pulls/comments` without the actual comment number. The weird part though is that both elements of the list you provide are the exact same, including `created_at` and `updated_at`. In any case, see my edited answer – Edo Akse Jun 14 '22 at 14:42
  • This is the url ,but I didn't paste the owner and repo https://api.github.com/repos/sample_owner/sample_repo/issues/1/comments, besides do are you familar with webhook? Do you know how the code should look like if I want to reject a pullrequest didn't specify some keywords in the comment? – bbq123 Jun 14 '22 at 16:27
  • so the reason why you're getting a list instead of a dict is because you're not using the endpoint you state in your question. You are pulling all comments from that issue, which is not exactly the same as pulling a single comment from a pull request. Please note that when asking a question, if you are not precise, you're going to get wrong answers, as we cannot know you wanted to do something different from the question you actually ask. Please reformulate your question (or open a new one) with exactly what it is you're trying to do, and what issues you're encountering... – Edo Akse Jun 15 '22 at 08:56
  • as to the exact answer to the question you pose, flakes was correct in his first comment, you are not calling the API for a single comment, you are calling the API for all comments, which is exactly why you're getting a list of dict elements, instead of a single dict element. – Edo Akse Jun 15 '22 at 08:58